martes, 27 de julio de 2010

Spring Web Services y MTOM Parte 2

Continuando con el post anterior ahora les voy a presentar el cliente del servicio web implementando mediante saaj y axiom integrado a spring. Veamos:

El cliente se despliega de la siguiente manera:

1. Maven ejecuta la clase principal CalculadoraClientWebServiceZip mediante un plugin:



org.codehaus.mojo
exec-maven-plugin
1.1.1



java




pe.com.slcsccy.pc.springws.client.CalculadoraClientWebServiceZip




2. La clase CalculadoraClientWebServiceZip crea los beans que se conectaran con el web service, este contenedor de beans se llama applicationContextZip.xml:



xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">









C:\\logs\spring.config



































Una vez creados los beans anteriores la aplicación cliente llamará al bean 'clienteWebServiceSaaj' y ejecutará el método enviarZip(nombreArchivo), este buscará en el sistema de archivos el archivo zip y lo enviará al web service, para poder hacer esto es necesario que previamente se hayan creado los proxies del web service mediante una llamada a la meta maven 'jaxb2:xjc', está meta buscará el schema XSD y generará las fuentes java, es decir realizará el binding entre el web service y su cliente. El plugin que implementa la meta maven se ejecuta como parte del proceso generate sources de maven, pero para evitar que eclipse me muestre errores de compilación la ejecuto antes:



org.codehaus.mojo
jaxb2-maven-plugin
1.3



xjc




src/main/resources
src/main/java
pe.com.slcsccy.pc.springws.client.schema
false




La clase que crea el mensaje de envío al web service y que recepciona su respuesta mediante Saaj es la siguiente:CalculadoraClientSaajMTOM.java


package pe.com.slcsccy.pc.springws.client;

import javax.activation.DataHandler;
import javax.activation.FileDataSource;

import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
import org.springframework.ws.soap.saaj.SaajSoapMessageFactory;

import pe.com.slcsccy.pc.springws.client.schema.MensajeRequest;
import pe.com.slcsccy.pc.springws.client.schema.MensajeResponse;
import pe.com.slcsccy.pc.springws.client.schema.ObjectFactory;
import pe.com.slcsccy.pc.springws.client.schema.OperacionesZipType;

public class CalculadoraClientSaajMTOM extends WebServiceGatewaySupport {

private ObjectFactory objectFactory = new ObjectFactory();

public CalculadoraClientSaajMTOM(SaajSoapMessageFactory messageFactory) {
super(messageFactory);
}

public MensajeResponse enviarZip(String nombreArchivo){
MensajeRequest mensajeRequest = objectFactory.createMensajeRequest();
OperacionesZipType zipType = new OperacionesZipType();
zipType.setNombreArchivoZip(nombreArchivo);
DataHandler handler = new DataHandler(new FileDataSource(nombreArchivo));
zipType.setArchivoZip(handler);
mensajeRequest.setOperacionesZip(zipType);
Object respuesta = getWebServiceTemplate().marshalSendAndReceive(mensajeRequest);
return (MensajeResponse)respuesta;
}
}


La clase que realiza lo mismo que la anterior pero mediante Axiom es la siguiente:CalculadoraClientAxiomMTOM.java


package pe.com.slcsccy.pc.springws.client;

import java.io.IOException;
import java.util.Iterator;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.activation.FileDataSource;
import javax.xml.namespace.QName;
import javax.xml.transform.TransformerException;

import org.apache.axiom.om.OMAttribute;
import org.apache.axiom.om.OMElement;
import org.apache.axiom.om.OMNamespace;
import org.apache.axiom.om.OMOutputFormat;
import org.apache.axiom.om.OMText;
import org.apache.axiom.soap.SOAPBody;
import org.apache.axiom.soap.SOAPEnvelope;
import org.apache.axiom.soap.SOAPFactory;
import org.apache.axiom.soap.SOAPMessage;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.core.WebServiceMessageCallback;
import org.springframework.ws.client.core.WebServiceMessageExtractor;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
import org.springframework.ws.soap.axiom.AxiomSoapMessage;
import org.springframework.ws.soap.axiom.AxiomSoapMessageFactory;

public class CalculadoraClientAxiomMTOM extends WebServiceGatewaySupport {

public CalculadoraClientAxiomMTOM(AxiomSoapMessageFactory messageFactory) {
super(messageFactory);
}

public void enviarZip(final String nombreArchivo){

WebServiceMessageCallback requestCallback = new WebServiceMessageCallback() {
public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException {
AxiomSoapMessage soapMessage = (AxiomSoapMessage) message;
SOAPMessage axiomMessage = soapMessage.getAxiomMessage();
SOAPFactory factory = (SOAPFactory) axiomMessage.getOMFactory();

//Armamos el contenido del mensaje:
SOAPBody cuerpoMensaje = axiomMessage.getSOAPEnvelope().getBody();
OMNamespace ns = factory.createOMNamespace("http://www.slcsccy.com.pe/pc/springws/calculadora", "calc");
OMElement mensajeRequestElement = factory.createOMElement("mensajeRequest",ns);
cuerpoMensaje.addChild(mensajeRequestElement);
OMElement operacionesZipElement = factory.createOMElement("operacionesZip", ns);

//Creo el archivo zip
OMAttribute nombreArchivoZipAttribute = factory.createOMAttribute("nombreArchivoZip",ns,nombreArchivo);
operacionesZipElement.addAttribute(nombreArchivoZipAttribute);
OMElement archivoZipElement = factory.createOMElement("archivoZip", ns);
DataSource dataSource = new FileDataSource(nombreArchivo);
DataHandler dataHandler = new DataHandler(dataSource);
OMText archivoZipText = factory.createOMText(dataHandler, true);
archivoZipElement.addChild(archivoZipText);
operacionesZipElement.addChild(archivoZipElement);
mensajeRequestElement.addChild(operacionesZipElement);

OMOutputFormat outputFormat = new OMOutputFormat();
outputFormat.setSOAP11(true);
outputFormat.setDoOptimize(true);
soapMessage.setOutputFormat(outputFormat);
}
};

WebServiceMessageExtractor responseExtractor = new WebServiceMessageExtractor() {
@SuppressWarnings("unchecked")
public Object extractData(WebServiceMessage message) throws IOException, TransformerException {
AxiomSoapMessage mensajeAxiom = (AxiomSoapMessage)message;
SOAPMessage mensaje = mensajeAxiom.getAxiomMessage();
SOAPEnvelope envelope = mensaje.getSOAPEnvelope();
SOAPBody body = envelope.getBody();

OMElement mensajeResponse = body.getFirstElement();
OMElement resultados = mensajeResponse.getFirstElement();

StringBuilder salida = new StringBuilder();
Iterator resultadosElement = resultados.getChildren();
QName atributoId = new QName("http://www.slcsccy.com.pe/pc/springws/calculadora","id");
while(resultadosElement.hasNext()){
OMElement elemento = resultadosElement.next();
salida.append("id:"+elemento.getAttributeValue(atributoId)+",valor:"+elemento.getText()+"\n");
}

logger.info("salida retorno:"+salida.toString());
return salida.toString();
}
};

@SuppressWarnings("unused")
String response = (String)getWebServiceTemplate().sendAndReceive(requestCallback,responseExtractor);
}
}



Una vez creado el proxy del web service ahora podemos conectarnos al web service y obtener los resultados esperados, veamos el log del cliente:


2010-07-27 23:35:27 (AbstractBeanFactory.java:241) - Returning cached instance of singleton bean 'clienteWebServiceSaaj'
2010-07-27 23:35:27 (WebServiceAccessor.java:110) - Opening [org.springframework.ws.transport.http.HttpUrlConnection@372a54] to [http://localhost:7001/springws/serviciosWeb]
2010-07-27 23:35:28 (WebServiceTemplate.java:581) - Sent request [SaajSoapMessage {http://www.slcsccy.com.pe/pc/springws/calculadora}mensajeRequest]
2010-07-27 23:35:35 (WebServiceTemplate.java:639) - Received response [SaajSoapMessage {http://www.slcsccy.com.pe/pc/springws/calculadora}mensajeResponse] for request [SaajSoapMessage {http://www.slcsccy.com.pe/pc/springws/calculadora}mensajeRequest]


Ahora veamos el log del web service:


2010-07-27 23:35:34 (WebServiceMessageReceiverObjectSupport.java:114) - Accepting incoming [org.springframework.ws.transport.http.HttpServletConnection@ea0dfc] to [http://localhost:7001/springws/serviciosWeb]
2010-07-27 23:35:34 (MessageDispatcher.java:167) - Received request [SaajSoapMessage {http://www.slcsccy.com.pe/pc/springws/calculadora}mensajeRequest]
2010-07-27 23:35:34 (AbstractMethodEndpointMapping.java:62) - Looking up endpoint for [{http://www.slcsccy.com.pe/pc/springws/calculadora}mensajeRequest]
2010-07-27 23:35:34 (MessageDispatcher.java:256) - Endpoint mapping [org.springframework.ws.server.endpoint.mapping.PayloadRootAnnotationMethodEndpointMapping@3311c0] maps request to endpoint [public pe.com.slcsccy.pc.springws.schema.MensajeResponse pe.com.slcsccy.pc.springws.ws.CalculadoraEndpointWithAnnotation.calcular(pe.com.slcsccy.pc.springws.schema.MensajeRequest) throws javax.xml.datatype.DatatypeConfigurationException,pe.com.slcsccy.pc.springws.exception.OperandoInvalidoException,pe.com.slcsccy.pc.springws.exception.UnzipException]
2010-07-27 23:35:34 (AbstractValidatingInterceptor.java:179) - Request message validated
2010-07-27 23:35:34 (AbstractLoggingInterceptor.java:160) - Request: UEsDBBQAAAAIAE26+TxJUMN0JgAAACgAAAAPAAAAb3BlcmFjaW9uZXMudHh0PcixCQAgEATB/OEa0RV8T9D+K/Mjs2EaOVlsRf+qS2ysGJxbr3hQSwECFAAUAAAACABNuvk8SVDDdCYAAAAoAAAADwAAAAAAAAAAACAAAAAAAAAAb3BlcmFjaW9uZXMudHh0UEsFBgAAAAABAAEAPQAAAFMAAAAAAA==
2010-07-27 23:35:34 (MessageDispatcher.java:277) - Testing endpoint adapter [org.springframework.ws.server.endpoint.adapter.GenericMarshallingMethodEndpointAdapter@1d33c09]
2010-07-27 23:35:35 (MarshallingMethodEndpointAdapter.java:146) - Unmarshalled payload request to [pe.com.slcsccy.pc.springws.schema.MensajeRequest@1ea9700]
2010-07-27 23:35:35 (AbstractBeanFactory.java:241) - Returning cached instance of singleton bean 'calculadoraEndpoint'
2010-07-27 23:35:35 (MarshallingMethodEndpointAdapter.java:153) - Marshalling [pe.com.slcsccy.pc.springws.schema.MensajeResponse@1fcbeda] to response payload
2010-07-27 23:35:35 (AbstractLoggingInterceptor.java:160) - Response: 8016108968
2010-07-27 23:35:35 (AbstractValidatingInterceptor.java:221) - Response message validated
2010-07-27 23:35:35 (MessageDispatcher.java:178) - Sent response [SaajSoapMessage {http://www.slcsccy.com.pe/pc/springws/calculadora}mensajeResponse] for request [SaajSoapMessage {http://www.slcsccy.com.pe/pc/springws/calculadora}mensajeRequest]
2010-07-27 23:35:35 (FrameworkServlet.java:677) - Successfully completed request


Con Axion el log en el cliente es el siguiente:


2010-07-27 23:43:35 (AbstractBeanFactory.java:241) - Returning cached instance of singleton bean 'lifecycleProcessor'
2010-07-27 23:43:35 (AbstractBeanFactory.java:241) - Returning cached instance of singleton bean 'clienteWebServiceAxiom'
2010-07-27 23:43:35 (WebServiceAccessor.java:110) - Opening [org.springframework.ws.transport.http.HttpUrlConnection@1f4d2b] to [http://localhost:7001/springws/serviciosWeb]
2010-07-27 23:43:35 (WebServiceTemplate.java:581) - Sent request [AxiomSoapMessage {http://www.slcsccy.com.pe/pc/springws/calculadora}mensajeRequest]
2010-07-27 23:43:35 (OMOutputFormat.java:140) - Start getContentType: OMOutputFormat [ mimeBoundary =null rootContentId=null doOptimize=true doingSWA=false isSOAP11=true charSetEncoding=null xmlVersion=null contentType=null ignoreXmlDeclaration=false autoCloseWriter=false actionProperty=null optimizedThreshold=0]
2010-07-27 23:43:35 (OMOutputFormat.java:166) - getContentType= {multipart/related; boundary="MIMEBoundary_be673ed239be738d78bcea194265e824bd3e5e2b92766546"; type="application/xop+xml"; start="<0.ae673ed239be738d78bcea194265e824bd3e5e2b92766546@apache.org>"; start-info="text/xml"} OMOutputFormat [ mimeBoundary =MIMEBoundary_be673ed239be738d78bcea194265e824bd3e5e2b92766546 rootContentId=0.ae673ed239be738d78bcea194265e824bd3e5e2b92766546@apache.org doOptimize=true doingSWA=false isSOAP11=true charSetEncoding=null xmlVersion=null contentType=text/xml ignoreXmlDeclaration=false autoCloseWriter=false actionProperty=null optimizedThreshold=0]
2010-07-27 23:43:35 (MTOMXMLStreamWriter.java:91) - OutputStream =class org.springframework.ws.transport.AbstractSenderConnection$RequestTransportOutputStream
2010-07-27 23:43:35 (MTOMXMLStreamWriter.java:92) - OMFormat = OMOutputFormat [ mimeBoundary =MIMEBoundary_be673ed239be738d78bcea194265e824bd3e5e2b92766546 rootContentId=0.ae673ed239be738d78bcea194265e824bd3e5e2b92766546@apache.org doOptimize=true doingSWA=false isSOAP11=true charSetEncoding=null xmlVersion=null contentType=text/xml ignoreXmlDeclaration=false autoCloseWriter=false actionProperty=null optimizedThreshold=0]
2010-07-27 23:43:35 (StAXUtils.java:615) - About to create XMLOutputFactory implementation with classloader=java.net.URLClassLoader@32d985
2010-07-27 23:43:35 (StAXUtils.java:617) - The classloader for javax.xml.stream.XMLOutputFactory is: null
2010-07-27 23:43:35 (StAXDialectDetector.java:219) - StAX implementation at jar:file:/I:/repo-maven/org/codehaus/woodstox/wstx-asl/3.2.9/wstx-asl-3.2.9.jar!/ is:
Title: WoodSToX XML-processor
Symbolic name: null
Vendor: woodstox.codehaus.org
Version: 3.2.9
2010-07-27 23:43:35 (StAXDialectDetector.java:181) - Detected StAX dialect: Woodstox
2010-07-27 23:43:35 (StAXUtils.java:635) - Created XMLOutputFactory = class org.apache.axiom.util.stax.wrapper.ImmutableXMLOutputFactory for classloader=java.net.URLClassLoader@32d985
2010-07-27 23:43:35 (StAXUtils.java:637) - Size of XMLOutputFactory map =1
2010-07-27 23:43:35 (StAXUtils.java:352) - XMLStreamWriter is org.apache.axiom.util.stax.dialect.WoodstoxStreamWriterWrapper
2010-07-27 23:43:35 (OptimizationPolicyImpl.java:60) - Start MTOMXMLStreamWriter.isOptimizedThreshold()
2010-07-27 23:43:35 (OptimizationPolicyImpl.java:65) - DataHandler fetched, starting optimized Threshold processing
2010-07-27 23:43:35 (OptimizationPolicyImpl.java:71) - node should be added to binart NodeList for optimization
2010-07-27 23:43:35 (MTOMXMLStreamWriter.java:182) - Calling MTOMXMLStreamWriter.flush
2010-07-27 23:43:35 (MTOMXMLStreamWriter.java:190) - The XML writing is completed. Now the attachments are written
2010-07-27 23:43:35 (MTOMXMLStreamWriter.java:172) - close
2010-07-27 23:43:36 (StAXSOAPModelBuilder.java:278) - Build the OMElement Envelope by the StaxSOAPModelBuilder
2010-07-27 23:43:36 (StAXSOAPModelBuilder.java:278) - Build the OMElement Header by the StaxSOAPModelBuilder
2010-07-27 23:43:36 (StAXSOAPModelBuilder.java:278) - Build the OMElement Body by the StaxSOAPModelBuilder
2010-07-27 23:43:36 (StAXSOAPModelBuilder.java:278) - Build the OMElement mensajeResponse by the StaxSOAPModelBuilder
2010-07-27 23:43:36 (WebServiceTemplate.java:639) - Received response [AxiomSoapMessage {http://www.slcsccy.com.pe/pc/springws/calculadora}mensajeResponse] for request [AxiomSoapMessage {http://www.slcsccy.com.pe/pc/springws/calculadora}mensajeRequest]
2010-07-27 23:43:36 (WebServiceTemplate.java:639) - Received response [AxiomSoapMessage {http://www.slcsccy.com.pe/pc/springws/calculadora}mensajeResponse] for request [AxiomSoapMessage {http://www.slcsccy.com.pe/pc/springws/calculadora}mensajeRequest]
2010-07-27 23:43:36 (StAXSOAPModelBuilder.java:278) - Build the OMElement resultados by the StaxSOAPModelBuilder
2010-07-27 23:43:36 (StAXSOAPModelBuilder.java:278) - Build the OMElement resultado by the StaxSOAPModelBuilder
2010-07-27 23:43:36 (StAXSOAPModelBuilder.java:278) - Build the OMElement resultado by the StaxSOAPModelBuilder
2010-07-27 23:43:36 (StAXSOAPModelBuilder.java:278) - Build the OMElement resultado by the StaxSOAPModelBuilder
2010-07-27 23:43:36 (StAXSOAPModelBuilder.java:278) - Build the OMElement resultado by the StaxSOAPModelBuilder


El proyecto completo en eclipse te lo puedes bajar desde AQUI

lunes, 26 de julio de 2010

Spring Web Services y MTOM Parte 1

Hola que tal hace tiempo que no posteaba, así que decidí hacerlo con un nuevo tema, el de los web services, el tema tiene que ver con la arquitectura orientada a servicios que estoy analizando desde hace un par de meses así que para recordar algo de los web services decidí implementar uno con spring web services; allí les va la definición simple del caso de uso que implementé:

CUS: Calcular operaciones matemáticas.

Descripción breve del CUS: El CUS permitirá al usuario del web service calcular operaciones matemáticas de suma, resta, multiplicación y división, la información enviada al servicio web podrá estar en formato XML o en un archivo de texto comprimido en formato zip que el web service procesará y generará la información en formato XML.

Un ejemplo de mensaje XML enviado al servidor será:



xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">



12
13




22
5







Cuando implementamos web services lo podemos hacer mediante un servlet o un enterprise java bean(EJB) en este caso como estoy usando spring la implementación será con un servlet, por lo que nuestra aplicación será un empaquetado WAR(Web ARchive), ahora una vez definido como será deployado el web service, debemos definir como será diseñado, el diseño de los web services puede realizarse de dos maneras:

(1)Primero escribimos código java que implemente el web service y una vez terminado de codificado, lo deployamos en nuestro servidor de aplicaciones favorito y es éste ultimo quien creará la descripción de nuestro servicio web inspeccionando las clases anotadas con @WebService. Este tipo de diseño se conoce como 'JAVA to WSDL' ó primero java.

(2)Primero escribimos el contrato del web service, el contrato en toda especificación de componente de software es la descripción detallada de mensajes intercambiados entre este componente y su entorno, en el caso de los web services el contrato o especificación es el descriptor del servicio web(WSDL). Este tipo de diseño se conoce como 'WSDL to JAVA' ó primero el contrato.


Como voy a usar spring para implementar mi web service lo primero que tengo que hacer es definir el formato de los mensajes aceptados por mi web service así como el formato de los mensajes de respuesta de mi web service. Esta definición la realizo en un schema XSD:




elementFormDefault="qualified" attributeFormDefault="qualified"
targetNamespace="http://www.slcsccy.com.pe/pc/springws/calculadora"
xmlns:calc="http://www.slcsccy.com.pe/pc/springws/calculadora"
xmlns:xmime="http://www.w3.org/2005/05/xmlmime">












maxOccurs="unbounded" />






































type="xs:decimal" />


























El schema anterior me define los mensajes de entrada al web service y el formato de mensaje de respuesta.


Ahora veamos el descriptor de despliegue de la aplicación web:



xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd">

Servicio web simple que implementa una calculadora


calculadora-annotation
org.springframework.ws.transport.http.MessageDispatcherServlet

transformWsdlLocations
true




calculadora-annotation
/*




El descriptor anterior define el servlet calculadora-annotation-servlet.xml en forma implicita, dicho contenedor de beans es el siguiente:




xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xmlns:sws="http://www.springframework.org/schema/web-services"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-1.5.xsd
http://www.springframework.org/schema/web-services http://www.springframework.org/schema/web-services/web-services-1.5.xsd">







C:\\logs\spring.config





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















class="org.springframework.ws.soap.server.endpoint.interceptor.PayloadValidatingInterceptor">






































A continuación veamos la clase principal que implementa el web service mediante anotaciones de spring:



package pe.com.slcsccy.pc.springws.ws;

import java.io.ByteArrayOutputStream;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.zip.ZipInputStream;

import javax.activation.DataHandler;
import javax.activation.DataSource;
import javax.xml.datatype.DatatypeConfigurationException;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.ws.server.endpoint.annotation.Endpoint;
import org.springframework.ws.server.endpoint.annotation.PayloadRoot;

import pe.com.slcsccy.pc.springws.domain.Operacion;
import pe.com.slcsccy.pc.springws.exception.OperandoInvalidoException;
import pe.com.slcsccy.pc.springws.exception.UnzipException;
import pe.com.slcsccy.pc.springws.schema.MensajeRequest;
import pe.com.slcsccy.pc.springws.schema.MensajeResponse;
import pe.com.slcsccy.pc.springws.schema.ObjectFactory;
import pe.com.slcsccy.pc.springws.schema.OperacionType;
import pe.com.slcsccy.pc.springws.schema.OperacionesZipType;
import pe.com.slcsccy.pc.springws.schema.ResultadoType;
import pe.com.slcsccy.pc.springws.schema.MensajeResponse.Resultados;
import pe.com.slcsccy.pc.springws.service.CalculadoraService;

@Endpoint
public class CalculadoraEndpointWithAnnotation {

private final Log logger = LogFactory.getLog(CalculadoraEndpointWithAnnotation.class);
public static final String NAMESPACE_URI = "http://www.slcsccy.com.pe/pc/springws/calculadora";
public static final String REQUEST_LOCAL_NAME = "mensajeRequest";
public static final String RESPONSE_LOCAL_NAME = "mensajeResponse";
private ObjectFactory objectFactory = new ObjectFactory();

private CalculadoraService calculadoraService;


/**
* Antes de la ejecución de este método la declaración:
* <sws:marshalling-endpoints marshaller="formador" unmarshaller="formador"/>
* se a encargado de crear el arbol de objetos desde un archivo xml, hay
* que recordar que el servicio web recibe XML y que es spring integrado con
* JAXB quién realiza el proceso de unmarshalling y marshalling para crear el
* arbol de objetos(MensajeRequest) y el formato de respuesta respectivamente.
* */
@PayloadRoot(localPart = REQUEST_LOCAL_NAME, namespace = NAMESPACE_URI)
public MensajeResponse calcular(MensajeRequest request)
throws DatatypeConfigurationException,OperandoInvalidoException,UnzipException {
logger.info("Mensaje recibido.");

//Empiezo a crear el objeto de respuesta
MensajeResponse response = objectFactory.createMensajeResponse();
Resultados resultados = objectFactory.createMensajeResponseResultados();
response.setResultados(resultados);

//Si el cliente del servicio web envió las operaciones en formato XML
if(request.getOperaciones()!=null){
List<OperacionType> operaciones = request.getOperaciones().getOperacion();
for(OperacionType operacion:operaciones){
if( operacion.getOperador().equals("/") &&
operacion.getOperandos().getOperando().get(1).equals(BigDecimal.ZERO))
throw new OperandoInvalidoException("No se puede dividir por cero.");

BigDecimal calculo = calculadoraService.calcular(operacion.getOperandos().getOperando(), operacion.getOperador());
ResultadoType resultado = objectFactory.createResultadoType();
resultado.setId(operacion.getId());//Copio los identificadores.
resultado.setValue(calculo);
resultados.getResultado().add(resultado);
logger.info("Respuesta calculada en el server:"+calculo.toPlainString());
}
}
else{
//Si no me enviaron las operaciones en formato XML, entonces me las
//enviaron en un archivo comprimido en formato zip:
OperacionesZipType operacionesZip = request.getOperacionesZip();
String archivoAsString = unzipOperaciones(operacionesZip.getArchivoZip());
List<Operacion> operacionesDomain = crearOperaciones(archivoAsString);
int idSecuencial = 1;
for(Operacion operacion:operacionesDomain){
BigDecimal calculo = calculadoraService.calcular(operacion.getOperandos(), operacion.getOperador());
ResultadoType resultado = objectFactory.createResultadoType();
resultado.setId(String.valueOf(idSecuencial++));
resultado.setValue(calculo);
resultados.getResultado().add(resultado);
logger.info("Respuesta calculada en el server:"+calculo.toPlainString());
}
}
return response;
}


/**
* Descomprime el archivo zip en una cadena
* */
private String unzipOperaciones(DataHandler handlerZip)throws UnzipException{
DataSource dataSource = null;
ZipInputStream zis = null;
String archivoAsString = null;
try{
dataSource = handlerZip.getDataSource();
zis = new ZipInputStream(dataSource.getInputStream());
if(zis.getNextEntry() != null){
int bytesLeidos = 0;
int BUFFER_SIZE = 1024*10;
byte buffer[] = new byte[BUFFER_SIZE];
ByteArrayOutputStream bos = new ByteArrayOutputStream();
while( (bytesLeidos = zis.read(buffer,0,BUFFER_SIZE)) != -1 ){
bos.write( buffer, 0, bytesLeidos);
}
archivoAsString = new String(bos.toByteArray());
}
zis.close();
}catch(Exception e){
logger.info("Error al leer el zip.",e);
throw new UnzipException("Error al leer el zip.");
}finally{
}
return archivoAsString;
}


/**
* Crea una lista de operaciones a partir de un cadena de texto.
* */
private List<Operacion> crearOperaciones(String archivoAsString){
Operacion operacion = null;
List<Operacion> operaciones = new ArrayList<Operacion>();
String[] lineas = archivoAsString.split("\n");
for(int i=0;i<lineas.length;i++){
logger.info("Linea a analizar:"+lineas[i]);
String[] operacionToken = lineas[i].split(",");
List<BigDecimal> operandos = new ArrayList<BigDecimal>();
for(int j=1;j<operacionToken.length;j++){
logger.info("Operador a procesar:"+operacionToken[j]);
operandos.add(new BigDecimal(operacionToken[j].trim()));
}
operacion = new Operacion(operacionToken[0],operandos);
operaciones.add(operacion);
}
return operaciones;
}


public CalculadoraService getCalculadoraService() {
return calculadoraService;
}


public void setCalculadoraService(CalculadoraService calculadoraService) {
this.calculadoraService = calculadoraService;
}
}


Como siempre para que el desarrollo sea más eficiente, generar fuentes con JAXB, compilar y deployar a weblogic uso MAVEN, el descriptor del proyecto es el siguiente:


xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
4.0.0
pe.com.slcsccy.pc
springws
war
0.0.1-SNAPSHOT
Aplicación de ejemplo básica de spring web services
http://maven.apache.org


2.9.1
t3
false
true
true
false
false
true
localhost
7001
ccacique
xxx
AdminServer
true




jdk14-jdk15

!1.6



javax.xml.stream
stax-api


javax.xml.soap
saaj-api







junit
junit
3.8.1
test


org.springframework.ws
spring-ws-core
2.0.0-M1


javax.xml.bind
jaxb-api
2.0



com.sun.xml.bind
jaxb-impl
2.0.3



log4j
log4j
1.2.16



springws


org.codehaus.mojo
jaxb2-maven-plugin
1.3



xjc




src/main/webapp/WEB-INF
src/main/java
pe.com.slcsccy.pc.springws.schema
false



org.apache.maven.plugins
maven-compiler-plugin

1.6
1.6



org.codehaus.mojo
weblogic-maven-plugin
${weblogic-maven-plugin.version}

${weblogic-maven-plugin.upload}
${weblogic-maven-plugin.verbose}
${weblogic-maven-plugin.debug}
${weblogic-maven-plugin.exploded}
${weblogic-maven-plugin.noExit}
${weblogic-maven-plugin.continueOnFailure}
${weblogic-maven-plugin.adminServerHostName}
${weblogic-maven-plugin.adminServerPort}
${weblogic-maven-plugin.adminServerProtocol}
${weblogic-maven-plugin.userId}
${weblogic-maven-plugin.password}
${weblogic-maven-plugin.remote}
${weblogic-maven-plugin.targetNames}



weblogic
wlfullclient
10.3


com.bea
com.bea.core.descriptor.wl
1.1.0.0








En el siguiente post expondré los clientes del web service que envía y reciben las respuestas del web service.


El proyecto completo en eclipse te lo puedes bajar desde AQUI