From d2b9b02c3f8c8175a0912c5952e9a224c8a118f8 Mon Sep 17 00:00:00 2001 From: Arjen Poutsma Date: Mon, 18 May 2009 10:14:46 +0000 Subject: [PATCH] SWS-496 - Added Axiom Spring-WS MTOM client --- .../ws/soap/axiom/AxiomSoapMessage.java | 60 ++++--- .../soap/axiom/AxiomSoapMessageFactory.java | 4 +- samples/mtom/client/spring-ws/build.xml | 4 +- .../mtom/client/sws/AxiomMtomClient.java | 150 ++++++++++++++++++ .../ws/samples/mtom/client/sws/Driver.java | 41 +++++ .../samples/mtom/client/sws/MtomClient.java | 65 -------- .../mtom/client/sws/SaajMtomClient.java | 82 ++++++++++ .../mtom/client/sws/applicationContext.xml | 14 +- .../mtom/service/StubImageRepository.java | 6 +- .../mtom/src/main/resources/log4j.properties | 4 +- 10 files changed, 336 insertions(+), 94 deletions(-) create mode 100644 samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/AxiomMtomClient.java create mode 100644 samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/Driver.java delete mode 100644 samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/MtomClient.java create mode 100644 samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/SaajMtomClient.java diff --git a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessage.java b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessage.java index 0933c35c..f8a534a3 100644 --- a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessage.java +++ b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessage.java @@ -1,5 +1,5 @@ /* - * Copyright 2006 the original author or authors. + * Copyright 2002-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -73,6 +73,8 @@ public class AxiomSoapMessage extends AbstractSoapMessage { private final boolean langAttributeOnSoap11FaulString; + private OMOutputFormat outputFormat; + /** * Create a new, empty AxiomSoapMessage. * @@ -154,6 +156,15 @@ public class AxiomSoapMessage extends AbstractSoapMessage { this.soapAction = EMPTY_SOAP_ACTION; } + /** + * Sets the {@link OMOutputFormat} to be used when writing the message. + * + * @see #writeTo(java.io.OutputStream) + */ + public void setOutputFormat(OMOutputFormat outputFormat) { + this.outputFormat = outputFormat; + } + public SoapEnvelope getEnvelope() { if (envelope == null) { try { @@ -212,24 +223,13 @@ public class AxiomSoapMessage extends AbstractSoapMessage { public void writeTo(OutputStream outputStream) throws IOException { try { - String charsetEncoding = axiomMessage.getCharsetEncoding(); - OMOutputFormat format = new OMOutputFormat(); - format.setCharSetEncoding(charsetEncoding); - format.setSOAP11(getVersion() == SoapVersion.SOAP_11); - boolean hasAttachments = !attachments.getContentIDSet().isEmpty(); - if (hasAttachments) { - if (isXopPackage()) { - format.setDoOptimize(true); - } - else { - format.setDoingSWA(true); - } - } + OMOutputFormat outputFormat = getOutputFormat(); if (outputStream instanceof TransportOutputStream) { TransportOutputStream transportOutputStream = (TransportOutputStream) outputStream; - String contentType = format.getContentType(); - if (!hasAttachments) { + String contentType = outputFormat.getContentType(); + if (!(outputFormat.isDoingSWA() || outputFormat.isOptimized())) { + String charsetEncoding = axiomMessage.getCharsetEncoding(); contentType += "; charset=" + charsetEncoding; } if (SoapVersion.SOAP_11 == getVersion()) { @@ -240,15 +240,15 @@ public class AxiomSoapMessage extends AbstractSoapMessage { } transportOutputStream.addHeader(TransportConstants.HEADER_CONTENT_TYPE, contentType); } - if (!(format.isOptimized()) & format.isDoingSWA()) { - writeSwAMessage(outputStream, format); + if (!(outputFormat.isOptimized()) & outputFormat.isDoingSWA()) { + writeSwAMessage(outputStream, outputFormat); } else { if (payloadCaching) { - axiomMessage.serialize(outputStream, format); + axiomMessage.serialize(outputStream, outputFormat); } else { - axiomMessage.serializeAndConsume(outputStream, format); + axiomMessage.serializeAndConsume(outputStream, outputFormat); } } outputStream.flush(); @@ -261,6 +261,26 @@ public class AxiomSoapMessage extends AbstractSoapMessage { } } + private OMOutputFormat getOutputFormat() { + if (outputFormat != null) { + return outputFormat; + } + else { + String charsetEncoding = axiomMessage.getCharsetEncoding(); + + OMOutputFormat outputFormat = new OMOutputFormat(); + outputFormat.setCharSetEncoding(charsetEncoding); + outputFormat.setSOAP11(getVersion() == SoapVersion.SOAP_11); + if (isXopPackage()) { + outputFormat.setDoOptimize(true); + } + else if (!attachments.getContentIDSet().isEmpty()) { + outputFormat.setDoingSWA(true); + } + return outputFormat; + } + } + private void writeSwAMessage(OutputStream outputStream, OMOutputFormat format) throws XMLStreamException, UnsupportedEncodingException { StringWriter writer = new StringWriter(); diff --git a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessageFactory.java b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessageFactory.java index c3590b8f..0f7b94ef 100644 --- a/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessageFactory.java +++ b/core/src/main/java/org/springframework/ws/soap/axiom/AxiomSoapMessageFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2006 the original author or authors. + * Copyright 2002-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -20,6 +20,7 @@ import java.io.File; import java.io.IOException; import java.io.InputStream; import java.util.Iterator; +import java.util.Locale; import javax.xml.stream.XMLInputFactory; import javax.xml.stream.XMLStreamException; import javax.xml.stream.XMLStreamReader; @@ -235,6 +236,7 @@ public class AxiomSoapMessageFactory implements SoapMessageFactory, Initializing } private boolean isMultiPartRelated(String contentType) { + contentType = contentType.toLowerCase(Locale.ENGLISH); return contentType.indexOf(MULTI_PART_RELATED_CONTENT_TYPE) != -1; } diff --git a/samples/mtom/client/spring-ws/build.xml b/samples/mtom/client/spring-ws/build.xml index df451513..d130468e 100644 --- a/samples/mtom/client/spring-ws/build.xml +++ b/samples/mtom/client/spring-ws/build.xml @@ -30,6 +30,8 @@ + + @@ -74,7 +76,7 @@ - + diff --git a/samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/AxiomMtomClient.java b/samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/AxiomMtomClient.java new file mode 100644 index 00000000..a6ec661e --- /dev/null +++ b/samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/AxiomMtomClient.java @@ -0,0 +1,150 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.samples.mtom.client.sws; + +import java.io.IOException; +import java.util.Iterator; +import javax.activation.DataHandler; +import javax.activation.DataSource; +import javax.activation.FileDataSource; +import javax.imageio.ImageIO; +import javax.xml.transform.TransformerException; + +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.SOAPFactory; +import org.apache.axiom.soap.SOAPMessage; + +import org.springframework.util.Assert; +import org.springframework.util.ClassUtils; +import org.springframework.util.StopWatch; +import org.springframework.util.StringUtils; +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; +import org.springframework.ws.soap.client.SoapFaultClientException; + +/** + * Simple client that demonstartes MTOM by invoking StoreImage and LoadImage using a + * WebServiceTemplate and Axiom. + * + * @author Arjen Poutsma + */ +public class AxiomMtomClient extends WebServiceGatewaySupport { + + private StopWatch stopWatch = new StopWatch(ClassUtils.getShortName(getClass())); + + public AxiomMtomClient(AxiomSoapMessageFactory messageFactory) { + super(messageFactory); + } + + public void doIt(String path) { + try { + store(path); + load(path); + System.out.println(stopWatch.prettyPrint()); + } + catch (SoapFaultClientException ex) { + System.err.format("SOAP Fault Code %1s%n", ex.getFaultCode()); + System.err.format("SOAP Fault String: %1s%n", ex.getFaultStringOrReason()); + } + + } + + private void store(final String path) { + stopWatch.start("store"); + getWebServiceTemplate().sendAndReceive(new WebServiceMessageCallback() { + public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException { + AxiomSoapMessage soapMessage = (AxiomSoapMessage) message; + SOAPMessage axiomMessage = soapMessage.getAxiomMessage(); + SOAPFactory factory = (SOAPFactory) axiomMessage.getOMFactory(); + SOAPBody body = axiomMessage.getSOAPEnvelope().getBody(); + + OMNamespace ns = + factory.createOMNamespace("http://www.springframework.org/spring-ws/samples/mtom", "tns"); + + OMElement storeImageRequestElement = factory.createOMElement("StoreImageRequest", ns); + body.addChild(storeImageRequestElement); + OMElement nameElement = factory.createOMElement("name", ns); + storeImageRequestElement.addChild(nameElement); + nameElement.setText(StringUtils.getFilename(path)); + OMElement imageElement = factory.createOMElement("image", ns); + storeImageRequestElement.addChild(imageElement); + DataSource dataSource = new FileDataSource(path); + DataHandler dataHandler = new DataHandler(dataSource); + OMText text = factory.createOMText(dataHandler, true); + imageElement.addChild(text); + + OMOutputFormat outputFormat = new OMOutputFormat(); + outputFormat.setSOAP11(true); + outputFormat.setDoOptimize(true); + soapMessage.setOutputFormat(outputFormat); + } + }, new WebServiceMessageExtractor() { + public Object extractData(WebServiceMessage message) throws IOException, TransformerException { + return null; + } + }); + stopWatch.stop(); + } + + private void load(final String path) { + final StringBuilder name = new StringBuilder(); + stopWatch.start("load"); + java.awt.Image image = (java.awt.Image) getWebServiceTemplate().sendAndReceive(new WebServiceMessageCallback() { + public void doWithMessage(WebServiceMessage message) throws IOException, TransformerException { + SOAPMessage axiomMessage = ((AxiomSoapMessage) message).getAxiomMessage(); + SOAPFactory factory = (SOAPFactory) axiomMessage.getOMFactory(); + SOAPBody body = axiomMessage.getSOAPEnvelope().getBody(); + + OMNamespace ns = + factory.createOMNamespace("http://www.springframework.org/spring-ws/samples/mtom", "tns"); + + OMElement loadImageRequestElement = factory.createOMElement("LoadImageRequest", ns); + loadImageRequestElement.setText(StringUtils.getFilename(path)); + body.addChild(loadImageRequestElement); + } + }, new WebServiceMessageExtractor() { + public Object extractData(WebServiceMessage message) throws IOException, TransformerException { + SOAPMessage axiomMessage = ((AxiomSoapMessage) message).getAxiomMessage(); + SOAPBody body = axiomMessage.getSOAPEnvelope().getBody(); + OMElement loadImageResponseElement = (OMElement) body.getChildElements().next(); + Assert.isTrue("LoadImageResponse".equals(loadImageResponseElement.getLocalName())); + Iterator childElements = loadImageResponseElement.getChildElements(); + OMElement nameElement = (OMElement) childElements.next(); + Assert.isTrue("name".equals(nameElement.getLocalName())); + name.append(nameElement.getText()); + OMElement imageElement = (OMElement) childElements.next(); + Assert.isTrue("image".equals(imageElement.getLocalName())); + OMText text = (OMText) imageElement.getFirstOMChild(); + + DataHandler dataHandler = (DataHandler) text.getDataHandler(); + return ImageIO.read(dataHandler.getInputStream()); + } + }); + stopWatch.stop(); + logger.info("Received image " + name + " [" + image.getWidth(null) + "x" + image.getHeight(null) + "]"); + } + + +} diff --git a/samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/Driver.java b/samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/Driver.java new file mode 100644 index 00000000..dff609b6 --- /dev/null +++ b/samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/Driver.java @@ -0,0 +1,41 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.samples.mtom.client.sws; + +import org.springframework.context.ApplicationContext; +import org.springframework.context.support.ClassPathXmlApplicationContext; + +public class Driver { + + public static void main(String[] args) { + if (args.length != 1) { + System.out.println("Usage: java " + Driver.class.getName() + " filePath"); + System.exit(-1); + } + String filePath = args[0]; + ApplicationContext applicationContext = + new ClassPathXmlApplicationContext("applicationContext.xml", Driver.class); + + SaajMtomClient saajClient = (SaajMtomClient) applicationContext.getBean("saajClient", SaajMtomClient.class); + saajClient.doIt(filePath); + + AxiomMtomClient axiomClient = + (AxiomMtomClient) applicationContext.getBean("axiomClient", AxiomMtomClient.class); + axiomClient.doIt(filePath); + } + +} diff --git a/samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/MtomClient.java b/samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/MtomClient.java deleted file mode 100644 index c79a953e..00000000 --- a/samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/MtomClient.java +++ /dev/null @@ -1,65 +0,0 @@ -/* - * Copyright 2002-2009 the original author or authors. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.springframework.ws.samples.mtom.client.sws; - -import java.awt.Toolkit; -import java.io.File; -import javax.xml.bind.JAXBElement; - -import org.springframework.context.ApplicationContext; -import org.springframework.context.support.ClassPathXmlApplicationContext; -import org.springframework.util.StopWatch; -import org.springframework.ws.client.core.support.WebServiceGatewaySupport; -import org.springframework.ws.soap.client.SoapFaultClientException; - -/** - * Simple client that demonstartes MTOM by invoking StoreImage and LoadImage using a - * WebServiceTemplate. - * - * @author Tareq Abed Rabbo - */ -public class MtomClient extends WebServiceGatewaySupport { - - public static void main(String[] args) { - try { - ApplicationContext applicationContext = - new ClassPathXmlApplicationContext("applicationContext.xml", MtomClient.class); - MtomClient client = (MtomClient) applicationContext.getBean("mtomClient", MtomClient.class); - - ObjectFactory objectFactory = new ObjectFactory(); - Image image = objectFactory.createImage(); - File file = new File(args[0]); - image.setName(file.getName()); - image.setImage(Toolkit.getDefaultToolkit().getImage(args[0])); - JAXBElement storeImageRequest = objectFactory.createStoreImageRequest(image); - StopWatch stopWatch = new StopWatch(); - stopWatch.start("store"); - client.getWebServiceTemplate().marshalSendAndReceive(storeImageRequest); - stopWatch.stop(); - JAXBElement loadImageRequest = objectFactory.createLoadImageRequest(file.getName()); - - stopWatch.start("load"); - Object result = client.getWebServiceTemplate().marshalSendAndReceive(loadImageRequest); - stopWatch.stop(); - System.out.println(stopWatch.prettyPrint()); - } - catch (SoapFaultClientException ex) { - System.err.format("SOAP Fault Code %1s%n", ex.getFaultCode()); - System.err.format("SOAP Fault String: %1s%n", ex.getFaultStringOrReason()); - } - } -} diff --git a/samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/SaajMtomClient.java b/samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/SaajMtomClient.java new file mode 100644 index 00000000..de78e430 --- /dev/null +++ b/samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/SaajMtomClient.java @@ -0,0 +1,82 @@ +/* + * Copyright 2002-2009 the original author or authors. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.springframework.ws.samples.mtom.client.sws; + +import java.awt.Toolkit; +import javax.xml.bind.JAXBElement; + +import org.springframework.util.ClassUtils; +import org.springframework.util.StopWatch; +import org.springframework.util.StringUtils; +import org.springframework.ws.client.core.support.WebServiceGatewaySupport; +import org.springframework.ws.soap.client.SoapFaultClientException; +import org.springframework.ws.soap.saaj.SaajSoapMessageFactory; + +/** + * Simple client that demonstartes MTOM by invoking StoreImage and LoadImage using a + * WebServiceTemplate and SAAJ. + * + * @author Tareq Abed Rabbo + * @author Arjen Poutsma + */ +public class SaajMtomClient extends WebServiceGatewaySupport { + + private ObjectFactory objectFactory = new ObjectFactory(); + + private StopWatch stopWatch = new StopWatch(ClassUtils.getShortName(getClass())); + + public SaajMtomClient(SaajSoapMessageFactory messageFactory) { + super(messageFactory); + } + + public void doIt(String path) { + try { + store(path); + load(path); + System.out.println(stopWatch.prettyPrint()); + } + catch (SoapFaultClientException ex) { + System.err.format("SOAP Fault Code %1s%n", ex.getFaultCode()); + System.err.format("SOAP Fault String: %1s%n", ex.getFaultStringOrReason()); + } + + } + + private void store(String path) { + Image image = objectFactory.createImage(); + image.setName(StringUtils.getFilename(path)); + image.setImage(Toolkit.getDefaultToolkit().getImage(path)); + JAXBElement storeImageRequest = objectFactory.createStoreImageRequest(image); + stopWatch.start("store"); + getWebServiceTemplate().marshalSendAndReceive(storeImageRequest); + stopWatch.stop(); + } + + private void load(String path) { + JAXBElement loadImageRequest = objectFactory.createLoadImageRequest(StringUtils.getFilename(path)); + + stopWatch.start("load"); + JAXBElement loadImageResponse = + (JAXBElement) getWebServiceTemplate().marshalSendAndReceive(loadImageRequest); + stopWatch.stop(); + Image image = loadImageResponse.getValue(); + logger.info("Received image " + image.getName() + " [" + image.getImage().getWidth(null) + "x" + + image.getImage().getHeight(null) + "]"); + + } + +} diff --git a/samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/applicationContext.xml b/samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/applicationContext.xml index cb472847..093d9d58 100644 --- a/samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/applicationContext.xml +++ b/samples/mtom/client/spring-ws/src/org/springframework/ws/samples/mtom/client/sws/applicationContext.xml @@ -2,8 +2,14 @@ - + + + + + + + @@ -13,4 +19,10 @@ + + + + + + diff --git a/samples/mtom/src/main/java/org/springframework/ws/samples/mtom/service/StubImageRepository.java b/samples/mtom/src/main/java/org/springframework/ws/samples/mtom/service/StubImageRepository.java index f8f8054d..163a228a 100644 --- a/samples/mtom/src/main/java/org/springframework/ws/samples/mtom/service/StubImageRepository.java +++ b/samples/mtom/src/main/java/org/springframework/ws/samples/mtom/service/StubImageRepository.java @@ -1,5 +1,5 @@ /* - * Copyright 2007 the original author or authors. + * Copyright 2002-2009 the original author or authors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -32,12 +32,12 @@ public class StubImageRepository implements ImageRepository { private Map images = new HashMap(); public Image readImage(String name) throws IOException { - logger.info("Streaming image " + name); + logger.info("Loading image " + name); return images.get(name); } public void storeImage(String name, Image image) throws IOException { - logger.info("Storing image " + name); + logger.info("Storing image " + name + " [" + image.getWidth(null) + "x" + image.getHeight(null) + "]"); images.put(name, image); } } diff --git a/samples/mtom/src/main/resources/log4j.properties b/samples/mtom/src/main/resources/log4j.properties index 9c1869de..ecbc6e2b 100644 --- a/samples/mtom/src/main/resources/log4j.properties +++ b/samples/mtom/src/main/resources/log4j.properties @@ -1,7 +1,5 @@ log4j.rootLogger=WARN, stdout -log4j.logger.org.springframework.ws=DEBUG -log4j.logger.org.springframework.oxm=DEBUG -log4j.logger.org.springframework.xml=DEBUG +log4j.logger.org.springframework.ws.samples=INFO log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.layout=org.apache.log4j.PatternLayout