You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commons-dev@ws.apache.org by ve...@apache.org on 2009/02/27 02:28:43 UTC

svn commit: r748368 - in /webservices/commons/trunk/modules/transport/modules: base/src/main/java/org/apache/axis2/format/ jms/src/main/java/org/apache/axis2/transport/jms/

Author: veithen
Date: Fri Feb 27 01:28:42 2009
New Revision: 748368

URL: http://svn.apache.org/viewvc?rev=748368&view=rev
Log:
Optimized processing of JMS BytesMessages with content type application/octet-stream by allowing the transport to pass a DataSource object instead of an InputStream to the message builder (BinaryBuilder in this case). The corresponding method is defined by a new optional interface DataSourceMessageBuilder. When this method is used, the message builder can process the message without creating a copy of the data.

Added:
    webservices/commons/trunk/modules/transport/modules/base/src/main/java/org/apache/axis2/format/DataSourceMessageBuilder.java   (with props)
    webservices/commons/trunk/modules/transport/modules/jms/src/main/java/org/apache/axis2/transport/jms/BytesMessageDataSource.java   (with props)
Modified:
    webservices/commons/trunk/modules/transport/modules/base/src/main/java/org/apache/axis2/format/BinaryBuilder.java
    webservices/commons/trunk/modules/transport/modules/jms/src/main/java/org/apache/axis2/transport/jms/BytesMessageInputStream.java
    webservices/commons/trunk/modules/transport/modules/jms/src/main/java/org/apache/axis2/transport/jms/JMSUtils.java

Modified: webservices/commons/trunk/modules/transport/modules/base/src/main/java/org/apache/axis2/format/BinaryBuilder.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/transport/modules/base/src/main/java/org/apache/axis2/format/BinaryBuilder.java?rev=748368&r1=748367&r2=748368&view=diff
==============================================================================
--- webservices/commons/trunk/modules/transport/modules/base/src/main/java/org/apache/axis2/format/BinaryBuilder.java (original)
+++ webservices/commons/trunk/modules/transport/modules/base/src/main/java/org/apache/axis2/format/BinaryBuilder.java Fri Feb 27 01:28:42 2009
@@ -22,6 +22,7 @@
 import java.io.InputStream;
 
 import javax.activation.DataHandler;
+import javax.activation.DataSource;
 import javax.xml.namespace.QName;
 
 import org.apache.axiom.attachments.ByteArrayDataSource;
@@ -29,7 +30,6 @@
 import org.apache.axiom.om.OMElement;
 import org.apache.axiom.om.OMFactory;
 import org.apache.axis2.AxisFault;
-import org.apache.axis2.builder.Builder;
 import org.apache.axis2.context.MessageContext;
 import org.apache.axis2.description.Parameter;
 import org.apache.commons.io.IOUtils;
@@ -44,8 +44,8 @@
  * be configured as a service parameter (see {@link BaseConstants#WRAPPER_PARAM}).
  * It defaults to {@link BaseConstants#DEFAULT_BINARY_WRAPPER}.
  */
-public class BinaryBuilder implements Builder {
-    public OMElement processDocument(InputStream inputStream,
+public class BinaryBuilder implements DataSourceMessageBuilder {
+    public OMElement processDocument(DataSource dataSource,
                                      String contentType,
                                      MessageContext msgContext) throws AxisFault {
         QName wrapperQName = BaseConstants.DEFAULT_BINARY_WRAPPER;
@@ -57,15 +57,22 @@
         }
         OMFactory factory = OMAbstractFactory.getOMFactory();
         OMElement wrapper = factory.createOMElement(wrapperQName, null);
+        DataHandler dataHandler = new DataHandler(dataSource);
+        wrapper.addChild(factory.createOMText(dataHandler, true));
+        msgContext.setDoingMTOM(true);
+        return wrapper;
+    }
+
+    public OMElement processDocument(InputStream inputStream,
+                                     String contentType,
+                                     MessageContext msgContext) throws AxisFault {
+        // TODO: this could be further optimized by deferring the read operation
         byte[] msgBytes;
         try {
             msgBytes = IOUtils.toByteArray(inputStream);
         } catch (IOException ex) {
             throw new AxisFault("Unable to read message payload", ex);
         }
-        DataHandler dataHandler = new DataHandler(new ByteArrayDataSource(msgBytes));
-        wrapper.addChild(factory.createOMText(dataHandler, true));
-        msgContext.setDoingMTOM(true);
-        return wrapper;
+        return processDocument(new ByteArrayDataSource(msgBytes), contentType, msgContext);
     }
 }

Added: webservices/commons/trunk/modules/transport/modules/base/src/main/java/org/apache/axis2/format/DataSourceMessageBuilder.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/transport/modules/base/src/main/java/org/apache/axis2/format/DataSourceMessageBuilder.java?rev=748368&view=auto
==============================================================================
--- webservices/commons/trunk/modules/transport/modules/base/src/main/java/org/apache/axis2/format/DataSourceMessageBuilder.java (added)
+++ webservices/commons/trunk/modules/transport/modules/base/src/main/java/org/apache/axis2/format/DataSourceMessageBuilder.java Fri Feb 27 01:28:42 2009
@@ -0,0 +1,57 @@
+/*
+ *  Licensed to the Apache Software Foundation (ASF) under one
+ *  or more contributor license agreements.  See the NOTICE file
+ *  distributed with this work for additional information
+ *  regarding copyright ownership.  The ASF licenses this file
+ *  to you 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.apache.axis2.format;
+
+import javax.activation.DataSource;
+
+import org.apache.axiom.om.OMElement;
+import org.apache.axis2.AxisFault;
+import org.apache.axis2.builder.Builder;
+import org.apache.axis2.context.MessageContext;
+
+/**
+ * Message builder able to build messages from {@link DataSource} objects.
+ * This interface can be optionally implemented by {@link Builder}
+ * implementations that support building messages from {@link DataSource} objects.
+ * Since by definition the data from a {@link DataSource} can be read multiple
+ * times, this interface can be used by message builders to avoid storing the
+ * message content in memory.
+ * <p>
+ * If a message builder implements this interface and the transport is able to
+ * provide the message payload as a data source, then the method defined by this
+ * interface should be preferred over the method defined by {@link Builder}.
+ * <p>
+ * When a message builder is invoked through the basic {@link Builder} interface,
+ * it is the responsibility of the transport to close the input stream once the
+ * message has been processed, and the builder is not required to consume the input
+ * stream immediately. On the other hand, when the builder is invoked through this extension
+ * interface, the transport is only responsible for ensuring that the {@link DataSource}
+ * remains valid for the whole lifecycle of the message. It is the responsibility of the
+ * builder to acquire the input stream and to make sure that it is closed when no longer
+ * needed. This important difference is the reason why there is no
+ * DataSourceMessageBuilderAdapter class.
+ * <p>
+ * Implementing this interface helps optimizing message processing with transports
+ * that use messaging providers that store messages in memory or on the file system.
+ * Examples are JMS and VFS.
+ */
+public interface DataSourceMessageBuilder extends Builder {
+    public OMElement processDocument(DataSource dataSource, String contentType,
+            MessageContext messageContext) throws AxisFault;
+}

Propchange: webservices/commons/trunk/modules/transport/modules/base/src/main/java/org/apache/axis2/format/DataSourceMessageBuilder.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: webservices/commons/trunk/modules/transport/modules/jms/src/main/java/org/apache/axis2/transport/jms/BytesMessageDataSource.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/transport/modules/jms/src/main/java/org/apache/axis2/transport/jms/BytesMessageDataSource.java?rev=748368&view=auto
==============================================================================
--- webservices/commons/trunk/modules/transport/modules/jms/src/main/java/org/apache/axis2/transport/jms/BytesMessageDataSource.java (added)
+++ webservices/commons/trunk/modules/transport/modules/jms/src/main/java/org/apache/axis2/transport/jms/BytesMessageDataSource.java Fri Feb 27 01:28:42 2009
@@ -0,0 +1,74 @@
+/*
+* Copyright 2004,2005 The Apache Software Foundation.
+*
+* 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.apache.axis2.transport.jms;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+import javax.jms.BytesMessage;
+import javax.jms.JMSException;
+
+import org.apache.axiom.attachments.SizeAwareDataSource;
+
+/**
+ * Data source implementation wrapping a JMS {@link BytesMessage}.
+ * <p>
+ * Note that two input streams created by the same instance of this
+ * class can not be used at the same time.
+ */
+public class BytesMessageDataSource implements SizeAwareDataSource {
+    private final BytesMessage message;
+    private final String contentType;
+
+    public BytesMessageDataSource(BytesMessage message, String contentType) {
+        this.message = message;
+        this.contentType = contentType;
+    }
+    
+    public BytesMessageDataSource(BytesMessage message) {
+        this(message, "application/octet-stream");
+    }
+
+    public long getSize() {
+        try {
+            return message.getBodyLength();
+        } catch (JMSException ex) {
+            throw new RuntimeException(ex);
+        }
+    }
+
+    public String getContentType() {
+        return contentType;
+    }
+
+    public InputStream getInputStream() throws IOException {
+        try {
+            message.reset();
+        } catch (JMSException ex) {
+            throw new JMSExceptionWrapper(ex);
+        }
+        return new BytesMessageInputStream(message);
+    }
+
+    public String getName() {
+        return null;
+    }
+
+    public OutputStream getOutputStream() throws IOException {
+        throw new UnsupportedOperationException();
+    }
+}

Propchange: webservices/commons/trunk/modules/transport/modules/jms/src/main/java/org/apache/axis2/transport/jms/BytesMessageDataSource.java
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: webservices/commons/trunk/modules/transport/modules/jms/src/main/java/org/apache/axis2/transport/jms/BytesMessageInputStream.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/transport/modules/jms/src/main/java/org/apache/axis2/transport/jms/BytesMessageInputStream.java?rev=748368&r1=748367&r2=748368&view=diff
==============================================================================
--- webservices/commons/trunk/modules/transport/modules/jms/src/main/java/org/apache/axis2/transport/jms/BytesMessageInputStream.java (original)
+++ webservices/commons/trunk/modules/transport/modules/jms/src/main/java/org/apache/axis2/transport/jms/BytesMessageInputStream.java Fri Feb 27 01:28:42 2009
@@ -23,6 +23,10 @@
 
 /**
  * Input stream that reads data from a JMS {@link BytesMessage}.
+ * Note that since the current position in the message is managed by
+ * the underlying {@link BytesMessage} object, it is not possible to
+ * use several instances of this class operating on a single
+ * {@link BytesMessage} at the same time.
  */
 public class BytesMessageInputStream extends InputStream {
     private final BytesMessage message;

Modified: webservices/commons/trunk/modules/transport/modules/jms/src/main/java/org/apache/axis2/transport/jms/JMSUtils.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/transport/modules/jms/src/main/java/org/apache/axis2/transport/jms/JMSUtils.java?rev=748368&r1=748367&r2=748368&view=diff
==============================================================================
--- webservices/commons/trunk/modules/transport/modules/jms/src/main/java/org/apache/axis2/transport/jms/JMSUtils.java (original)
+++ webservices/commons/trunk/modules/transport/modules/jms/src/main/java/org/apache/axis2/transport/jms/JMSUtils.java Fri Feb 27 01:28:42 2009
@@ -25,6 +25,7 @@
 import org.apache.axis2.context.MessageContext;
 import org.apache.axis2.description.AxisService;
 import org.apache.axis2.description.Parameter;
+import org.apache.axis2.format.DataSourceMessageBuilder;
 import org.apache.axis2.format.TextMessageBuilder;
 import org.apache.axis2.format.TextMessageBuilderAdapter;
 import org.apache.commons.logging.Log;
@@ -164,55 +165,51 @@
     public static void setSOAPEnvelope(Message message, MessageContext msgContext, String contentType)
         throws AxisFault, JMSException {
 
-        if (message instanceof BytesMessage) {
-            if (contentType == null) {
-                log.debug("No content type specified; assuming application/octet-stream.");
-                contentType = "application/octet-stream";
+        if (contentType == null) {
+            if (message instanceof TextMessage) {
+                contentType = "text/plain";
             } else {
-                // Extract the charset encoding from the content type and
-                // set the CHARACTER_SET_ENCODING property as e.g. SOAPBuilder relies on this.
-                String charSetEnc = null;
-                try {
-                    if (contentType != null) {
-                        charSetEnc = new ContentType(contentType).getParameter("charset");
-                    }
-                } catch (ParseException ex) {
-                    // ignore
-                }
-                msgContext.setProperty(Constants.Configuration.CHARACTER_SET_ENCODING, charSetEnc);
+                contentType = "application/octet-stream";
             }
-            
-            SOAPEnvelope envelope;
-            try {
-                envelope = TransportUtils.createSOAPMessage(msgContext,
-                        new BytesMessageInputStream((BytesMessage)message), contentType);
-            } catch (XMLStreamException ex) {
-                handleException("Error parsing XML", ex);
-                return; // Make compiler happy
+            if (log.isDebugEnabled()) {
+                log.debug("No content type specified; assuming " + contentType);
             }
-            msgContext.setEnvelope(envelope);
-
-        } else if (message instanceof TextMessage) {
-            String type;
-            if (contentType == null) {
-                log.debug("No content type specified; assuming text/plain.");
-                type = contentType = "text/plain";
-            } else {
-                int index = contentType.indexOf(';');
-                if (index > 0) {
-                    type = contentType.substring(0, index);
-                } else {
-                    type = contentType;
-                }
+        }
+        
+        int index = contentType.indexOf(';');
+        String type = index > 0 ? contentType.substring(0, index) : contentType;
+        Builder builder = BuilderUtil.getBuilderFromSelector(type, msgContext);
+        if (builder == null) {
+            if (log.isDebugEnabled()) {
+                log.debug("No message builder found for type '" + type + "'. Falling back to SOAP.");
             }
-            Builder builder = BuilderUtil.getBuilderFromSelector(type, msgContext);
-            if (builder == null) {
-                if (log.isDebugEnabled()) {
-                    log.debug("No message builder found for type '" + type + "'. Falling back to SOAP.");
+            builder = new SOAPBuilder();
+        }
+        
+        OMElement documentElement;
+        if (message instanceof BytesMessage) {
+            // Extract the charset encoding from the content type and
+            // set the CHARACTER_SET_ENCODING property as e.g. SOAPBuilder relies on this.
+            String charSetEnc = null;
+            try {
+                if (contentType != null) {
+                    charSetEnc = new ContentType(contentType).getParameter("charset");
                 }
-                builder = new SOAPBuilder();
+            } catch (ParseException ex) {
+                // ignore
             }
-
+            msgContext.setProperty(Constants.Configuration.CHARACTER_SET_ENCODING, charSetEnc);
+            
+            if (builder instanceof DataSourceMessageBuilder) {
+                documentElement = ((DataSourceMessageBuilder)builder).processDocument(
+                        new BytesMessageDataSource((BytesMessage)message), contentType,
+                        msgContext);
+            } else {
+                documentElement = builder.processDocument(
+                        new BytesMessageInputStream((BytesMessage)message), contentType,
+                        msgContext);
+            }
+        } else if (message instanceof TextMessage) {
             TextMessageBuilder textMessageBuilder;
             if (builder instanceof TextMessageBuilder) {
                 textMessageBuilder = (TextMessageBuilder)builder;
@@ -220,10 +217,12 @@
                 textMessageBuilder = new TextMessageBuilderAdapter(builder);
             }
             String content = ((TextMessage)message).getText();
-            OMElement documentElement
-                    = textMessageBuilder.processDocument(content, contentType, msgContext);
-            msgContext.setEnvelope(TransportUtils.createSOAPEnvelope(documentElement));
+            documentElement = textMessageBuilder.processDocument(content, contentType, msgContext);
+        } else {
+            handleException("Unsupported JMS message type " + message.getClass().getName());
+            return; // Make compiler happy
         }
+        msgContext.setEnvelope(TransportUtils.createSOAPEnvelope(documentElement));
     }
 
     /**