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 sc...@apache.org on 2008/01/14 22:37:00 UTC

svn commit: r611943 - in /webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments: ./ impl/ part/

Author: scheu
Date: Mon Jan 14 13:36:58 2008
New Revision: 611943

URL: http://svn.apache.org/viewvc?rev=611943&view=rev
Log:
WSCOMMONS-292
Contributor:Rich Scheuerle
Introduced PartFactory to control the logic to createPart objects.  This logic is moved out of Attachments.getPart.  In addition, I added new PartOnFile and PartOnMemory objects that are more buffer sensitive.  Removed the legacy PartOnFile, PartOnMemory, PartOnByteArray, etc. classes

Added:
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/AbstractPart.java
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/BufferUtils.java
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/PartFactory.java
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/PartOnFile.java
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/PartOnMemory.java
Removed:
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/PartOnFile.java
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/PartOnMemory.java
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/PushbackFilePartInputStream.java
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/part/
Modified:
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/Attachments.java
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEBodyPartInputStream.java
    webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/Part.java

Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/Attachments.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/Attachments.java?rev=611943&r1=611942&r2=611943&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/Attachments.java (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/Attachments.java Mon Jan 14 13:36:58 2008
@@ -19,6 +19,18 @@
 
 package org.apache.axiom.attachments;
 
+import org.apache.axiom.attachments.impl.PartFactory;
+import org.apache.axiom.om.OMException;
+import org.apache.axiom.om.impl.MTOMConstants;
+import org.apache.axiom.om.util.UUIDGenerator;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.activation.DataHandler;
+import javax.mail.MessagingException;
+import javax.mail.internet.ContentType;
+import javax.mail.internet.ParseException;
+
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PushbackInputStream;
@@ -28,18 +40,6 @@
 import java.util.Set;
 import java.util.TreeMap;
 
-import javax.activation.DataHandler;
-import javax.mail.MessagingException;
-import javax.mail.internet.ContentType;
-import javax.mail.internet.ParseException;
-
-import org.apache.axiom.attachments.part.DynamicPart;
-import org.apache.axiom.om.OMException;
-import org.apache.axiom.om.impl.MTOMConstants;
-import org.apache.axiom.om.util.UUIDGenerator;
-import org.apache.commons.logging.Log;
-import org.apache.commons.logging.LogFactory;
-
 public class Attachments {
 
     /** <code>ContentType</code> of the MIME message */
@@ -549,56 +549,22 @@
 
         partsRequested = true;
 
-        Part part;
+        boolean isSOAPPart = (partIndex == 0);
+        int threshhold = (fileCacheEnable) ? fileStorageThreshold : 0;
 
-        try {
-            if (fileCacheEnable) {
-                try {
-                    //If Content-Length defined.
-                    if(contentLength!=0){
-                        if (log.isDebugEnabled()) {
-                            log.debug("Fixed Content-Length Data");
-                        }
-                        MIMEBodyPartInputStream partStream =
-                            new MIMEBodyPartInputStream(pushbackInStream,
-                                                        boundary,
-                                                        this,
-                                                        PUSHBACK_SIZE);
-                        
-                        part = DynamicPart.createPart(contentLength, partIndex, partStream, attachmentRepoDir, fileStorageThreshold);
-                 
-                    } else {
-                        if (log.isDebugEnabled()) {
-                            log.debug("Chunked Data");
-                        }
-                        // Read chunks of data to determine the size
-                        // of the attachment.  This can wasteful because we need to gc the buffers.
-                        // TODO We could look at the content-length of the individual attachment; however
-                        // this is seldom provided.
-                        
-                        MIMEBodyPartInputStream partStream;
-                 
-                        partStream =
-                            new MIMEBodyPartInputStream(pushbackInStream,
-                                                        boundary,
-                                                        this,
-                                                        PUSHBACK_SIZE);
-                        part = DynamicPart.createPart(partStream, attachmentRepoDir, fileStorageThreshold);
-                        
-                    } 
-                } catch (Exception e) {
-                    throw new OMException("Error creating temporary File.", e);
-                }
-            } else {
-                MIMEBodyPartInputStream partStream;
-                partStream =
-                        new MIMEBodyPartInputStream(pushbackInStream, boundary, this, PUSHBACK_SIZE);
-                part = new PartOnMemory(partStream);
-            }
-
-        } catch (MessagingException e) {
-            throw new OMException(e);
-        }
+        // Create a MIMEBodyPartInputStream that simulates a single stream for this MIME body part
+        MIMEBodyPartInputStream partStream =
+            new MIMEBodyPartInputStream(pushbackInStream,
+                                        boundary,
+                                        this,
+                                        PUSHBACK_SIZE);
+
+        // The PartFactory will determine which Part implementation is most appropriate.
+        Part part = PartFactory.createPart(partStream, 
+                                      isSOAPPart, 
+                                      threshhold, 
+                                      attachmentRepoDir, 
+                                      contentLength);  // content-length for the whole message
         partIndex++;
         return part;
     }

Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEBodyPartInputStream.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEBodyPartInputStream.java?rev=611943&r1=611942&r2=611943&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEBodyPartInputStream.java (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEBodyPartInputStream.java Mon Jan 14 13:36:58 2008
@@ -24,7 +24,7 @@
 import java.io.PushbackInputStream;
 
 /**
- * @author scheu
+ * MIMEBodyPartInputStream
  *
  */
 public class MIMEBodyPartInputStream extends InputStream {

Modified: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/Part.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/Part.java?rev=611943&r1=611942&r2=611943&view=diff
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/Part.java (original)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/Part.java Mon Jan 14 13:36:58 2008
@@ -25,25 +25,80 @@
 import java.io.InputStream;
 import java.util.Enumeration;
 
+/**
+ * Abstract for Part.  A Part can be the SOAP Part or an Attachment Part.
+ * There are several implementations for part, which are optimized for 
+ * space and time.
+ * 
+ * A Part is created with the PartFactory.
+ * 
+ * @see org.apache.axiom.attachments.impl.PartFactory
+ */
 public interface Part {
 
 
+    /**
+     * @return DataHandler representing this part
+     * @throws MessagingException
+     */
+    public DataHandler getDataHandler() throws MessagingException;
+    
+    /**
+     * @return size
+     * @throws MessagingException
+     */
     public int getSize() throws MessagingException;
 
+    /**
+     * @return content type of the part
+     * @throws MessagingException
+     */
     public String getContentType() throws MessagingException;
 
+    /**
+     * @return content id of the part
+     * @throws MessagingException
+     */
     public String getContentID() throws MessagingException;
 
+    /**
+     * The part may be backed by a file.  If that is the case,
+     * this method returns the file name.
+     * 
+     * @return 
+     * @throws MessagingException
+     * @deprecated The callers should not no how the part 
+     * is implemented.
+     */
     public String getFileName() throws MessagingException;
 
+    /**
+     * @return Get the part data as an input stream
+     * @throws IOException
+     * @throws MessagingException
+     */
     public InputStream getInputStream() throws IOException, MessagingException;
 
-    public DataHandler getDataHandler() throws MessagingException;
-
-    public void addHeader(String arg0, String arg1) throws MessagingException;
-
-    public String getHeader(String arg0) throws MessagingException;
-
+    /**
+     * Add a Header (name, value) to the part
+     * @param name
+     * @param value
+     * @throws MessagingException
+     */
+    public void addHeader(String name, String value) throws MessagingException;
+
+    /**
+     * Get the value of a specific header
+     * @param name
+     * @return value or null
+     * @throws MessagingException
+     */
+    public String getHeader(String name) throws MessagingException;
+
+    /**
+     * @return Enumeration of javax.mail.Header
+     * @throws MessagingException
+     */
     public Enumeration getAllHeaders() throws MessagingException;
 
 }

Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/AbstractPart.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/AbstractPart.java?rev=611943&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/AbstractPart.java (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/AbstractPart.java Mon Jan 14 13:36:58 2008
@@ -0,0 +1,153 @@
+/*
+ * 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.axiom.attachments.impl;
+
+import org.apache.axiom.attachments.Part;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.activation.DataHandler;
+import javax.mail.Header;
+import javax.mail.MessagingException;
+import javax.mail.internet.HeaderTokenizer;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Enumeration;
+import java.util.Hashtable;
+
+/**
+ * AbstractPart is a base class for the actual 
+ * Part implementations.  The primary purpose of AbstractPart is
+ * to define some of the common methods to promote code reuse.
+ */
+abstract class AbstractPart implements Part {
+
+    private static Log log = LogFactory.getLog(AbstractPart.class);
+                                                 
+    // Key is the lower-case name.
+    // Value is a javax.mail.Header object
+    private Hashtable headers;
+    
+    
+    /**
+     * The actual parts are constructed with the PartFactory.
+     * @see org.apache.axiom.attachments.impl.PartFactory
+     * @param headers
+     */
+    AbstractPart(Hashtable in) {
+        headers = in;
+        if (headers == null) {
+            headers = new Hashtable();
+        }
+    }
+    
+    public void addHeader(String name, String value) {
+        if (log.isDebugEnabled()){
+            log.debug("addHeader: (" + name + ") value=(" + value +")");
+        }
+        Header headerObj = new Header(name, value);
+        
+        // Use the lower case name as the key
+        String key = name.toLowerCase();
+        headers.put(key, headerObj);
+    }
+
+    public Enumeration getAllHeaders() throws MessagingException {
+        if(log.isDebugEnabled()){
+            log.debug("getAllHeaders");
+        }
+        return headers.elements();
+    }
+    
+    public String getHeader(String name) {
+        String key = name.toLowerCase();
+        Header header = (Header) headers.get(key);
+        String value = header == null ? null : header.getValue();
+        if(log.isDebugEnabled()){
+            log.debug("getHeader name=(" + name + ") value=(" + value +")");
+        }
+        return value;
+    }
+
+    public String getContentID() throws MessagingException {
+        return getHeader("content-id");
+    }
+
+    public String getContentType() throws MessagingException {
+        return getHeader("content-type");
+    }
+    
+    /**
+     * @return contentTransferEncoding
+     * @throws MessagingException
+     */
+    public String getContentTransferEncoding() throws MessagingException {
+        if(log.isDebugEnabled()){
+            log.debug("getContentTransferEncoding()");
+        }
+        String cte = getHeader("content-transfer-encoding");
+       
+        if(log.isDebugEnabled()){
+            log.debug(" CTE =" + cte);
+        }
+
+        if(cte!=null){
+            cte = cte.trim();
+            
+            if(cte.equalsIgnoreCase("7bit") || 
+                cte.equalsIgnoreCase("8bit") ||
+                cte.equalsIgnoreCase("quoted-printable") ||
+                cte.equalsIgnoreCase("base64")){
+
+                return cte;
+            }
+            
+            HeaderTokenizer ht = new HeaderTokenizer(cte, HeaderTokenizer.MIME);
+            boolean done = false;
+            while(!done){
+                HeaderTokenizer.Token token = ht.next();
+                switch(token.getType()){
+                case HeaderTokenizer.Token.EOF:
+                    if(log.isDebugEnabled()){
+                        log.debug("HeaderTokenizer EOF");
+                    }
+                    done = true;
+                    break;
+                case HeaderTokenizer.Token.ATOM:                    
+                    return token.getValue();
+                }
+            }
+            return cte;
+        }
+        return null;
+
+
+    }
+
+    // The following classes must be implemented by the derived class.
+    public abstract DataHandler getDataHandler() throws MessagingException;
+    
+    public abstract String getFileName() throws MessagingException;
+
+    public abstract InputStream getInputStream() throws IOException, MessagingException;
+
+    public abstract int getSize() throws MessagingException;
+
+}

Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/BufferUtils.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/BufferUtils.java?rev=611943&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/BufferUtils.java (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/BufferUtils.java Mon Jan 14 13:36:58 2008
@@ -0,0 +1,87 @@
+/*
+ * 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.axiom.attachments.impl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+/**
+ * Attachment processing uses a lot of buffers.
+ * The BufferUtils class attempts to reuse buffers to prevent 
+ * excessive GarbageCollection
+ */
+public class BufferUtils {
+    
+    public static final int BUFFER_LEN = 16 * 1024;
+    
+    /**
+     * Private utility to write the InputStream contents to the OutputStream.
+     * @param is
+     * @param os
+     * @throws IOException
+     */
+    public static void inputStream2OutputStream(InputStream is, 
+                                                OutputStream os)
+        throws IOException {
+            
+        
+        byte[] buffer = new byte[BUFFER_LEN];
+        int bytesRead = is.read(buffer);
+        
+        // Continue reading until no bytes are read and no
+        // bytes are now available.
+        while (bytesRead > 0 || is.available() > 0) {
+            os.write(buffer, 0, bytesRead);
+            bytesRead = is.read(buffer);
+        }
+        
+    }
+    
+    /**
+     * @param is InputStream
+     * @param os OutputStream
+     * @param limit maximum number of bytes to read
+     * @return total ytes read
+     * @throws IOException
+     */
+    public static int inputStream2OutputStream(InputStream is, 
+                                                OutputStream os,
+                                                int limit) 
+        throws IOException {
+            
+        byte[] buffer = new byte[BUFFER_LEN];
+        int totalWritten = 0;
+        int bytesRead = 0;
+        
+        do {
+            int len = (limit-totalWritten) > BUFFER_LEN ? BUFFER_LEN : (limit-totalWritten);
+            bytesRead = is.read(buffer, 0, len);
+            if (bytesRead > 0) {
+                os.write(buffer, 0, bytesRead);
+                if (bytesRead > 0) {
+                    totalWritten += bytesRead;
+                }
+            }
+        } while (totalWritten < limit && (bytesRead > 0 || is.available() > 0));
+        return totalWritten;
+    }
+    
+  
+}

Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/PartFactory.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/PartFactory.java?rev=611943&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/PartFactory.java (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/PartFactory.java Mon Jan 14 13:36:58 2008
@@ -0,0 +1,205 @@
+/*
+ * 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.axiom.attachments.impl;
+
+import org.apache.axiom.attachments.MIMEBodyPartInputStream;
+import org.apache.axiom.attachments.Part;
+import org.apache.axiom.om.OMException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.mail.Header;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Hashtable;
+import java.util.Map;
+
+/**
+ * The PartFactory creates an object that represents a Part
+ * (implements the Part interface).  There are different ways
+ * to represent a part (backing file or backing array etc.).
+ * These different implementations should not be exposed to the 
+ * other layers of the code.  The PartFactory helps maintain this
+ * abstraction, and makes it easier to add new implementations.
+ */
+public class PartFactory {
+    
+    private static Log log = LogFactory.getLog(PartFactory.class);
+    
+    /**
+     * Creates a part from the input stream.
+     * The remaining parameters are used to determine if the
+     * part should be represented in memory (byte buffers) or
+     * backed by a file.
+     * 
+     * @param in MIMEBodyPartInputStream
+     * @param isSOAPPart
+     * @param threshholdSize
+     * @param attachmentDir
+     * @param messageContentLength
+     * @return Part
+     * @throws OMException if any exception is encountered while processing.
+     */
+    public static Part createPart(MIMEBodyPartInputStream in,
+                    boolean isSOAPPart,
+                    int threshholdSize,
+                    String attachmentDir,
+                    int messageContentLength
+                    ) throws OMException {
+        if(log.isDebugEnabled()){
+            log.debug("Start createPart()");
+            log.debug("  isSOAPPart=" + isSOAPPart);
+            log.debug("  threshholdSize= " + threshholdSize);
+            log.debug("  attachmentDir=" + attachmentDir);
+            log.debug("  messageContentLength " + messageContentLength);
+        }
+        
+        try {
+            // Read enough of the InputStream to build the headers 
+            Hashtable headers = new Hashtable();
+            readHeaders(in, headers);
+            
+            
+            if (isSOAPPart ||
+                    threshholdSize <= 0 ||  
+                    (messageContentLength > 0 && 
+                            messageContentLength < threshholdSize)) {
+                // If the entire message is less than the threshold size, 
+                // keep it in memory.
+                // If this is a SOAPPart, keep it in memory.
+                
+                // Get the bytes of the data without a lot 
+                // of resizing and GC.  For now I will write to a
+                // private BAOS and get the byte buffer from it.
+                BAOS baos = new BAOS();
+                BufferUtils.inputStream2OutputStream(in, baos);
+                return new PartOnMemory(headers, baos.toByteArray(), baos.size());
+            } else {
+                // We need to read the input stream to determine whether
+                // the size is bigger or smaller than the threshhold.
+                BAOS baos = new BAOS();
+                int total = BufferUtils.inputStream2OutputStream(in, baos, threshholdSize);
+                if (total < threshholdSize) {
+                    return new PartOnMemory(headers, baos.toByteArray(), baos.size());
+                } else {
+                    ByteArrayInputStream bais = 
+                        new ByteArrayInputStream(baos.toByteArray(), 0, baos.size());
+                    
+                    return new PartOnFile(headers, 
+                                          bais,
+                                          in, 
+                                          attachmentDir);
+                }
+                
+            }
+            
+        } catch (Exception e) {
+            throw new OMException(e);
+        } 
+    }
+    
+    /**
+     * The implementing class must call initHeaders prior to using
+     * any of the Part methods.  
+     * @param is
+     * @param headers
+     */
+    private static void readHeaders(InputStream in, Map headers) throws IOException {
+        int ch;
+        if(log.isDebugEnabled()){
+            log.debug("initHeaders");
+        }
+        boolean done = false;
+        
+        // Read the characters into a StringBuffer and
+        // add each header to the map
+        StringBuffer sb = new StringBuffer(50);
+        while (!done && (ch = in.read()) != -1) {
+            if (ch == 13) {
+                if ((ch = in.read()) == 10) {
+                    if ((ch = in.read()) == 13) {
+                        if ((ch = in.read()) == 10) {
+                            // Blank line indicates we are done.
+                            readHeader(sb, headers);
+                            sb.delete(0, sb.length()); // Clear the buffer for reuse
+                            done = true;
+                        }
+                    } else {
+                        // now parse and add the header String
+                        readHeader(sb, headers);
+                        sb.delete(0, sb.length()); // Clear the buffer for reuse
+                        sb.append((char) ch);
+                    }
+                } else {
+                    sb.append(13);
+                    sb.append((char) ch);
+                }
+            } else {
+                sb.append((char) ch);
+            }
+        }
+        if(log.isDebugEnabled()){
+            log.debug("End initHeaders");
+        }
+        return;
+    }
+    
+    /**
+     * Parse the header into a name and value pair.
+     * Add the name value pair to the map.
+     * @param header StringBuffer
+     * @param headers Map
+     */
+    private static void readHeader(StringBuffer header, Map headers) {
+        int delimiter = header.indexOf(":");
+        String name = header.substring(0, delimiter).trim();
+        String value = header.substring(delimiter + 1, header.length()).trim();
+        
+        if (log.isDebugEnabled()){
+            log.debug("addHeader: (" + name + ") value=(" + value +")");
+        }
+        Header headerObj = new Header(name, value);
+        
+        // Use the lower case name as the key
+        String key = name.toLowerCase();
+        headers.put(key, headerObj);
+    }
+    
+    /**
+     * A normal ByteArrayOutputStream, except that it returns the buffer
+     * directly instead of returning a copy of the buffer.
+     */
+    static class BAOS extends ByteArrayOutputStream {
+
+        /**
+         * Create a BAOS with a decent sized buffer
+         */
+        public BAOS() {
+            super(16 * 1024);
+        }
+
+        public byte[] toByteArray() {
+            return buf;
+        }
+        
+    }
+}

Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/PartOnFile.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/PartOnFile.java?rev=611943&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/PartOnFile.java (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/PartOnFile.java Mon Jan 14 13:36:58 2008
@@ -0,0 +1,128 @@
+/*
+ * 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.axiom.attachments.impl;
+
+import org.apache.axiom.attachments.CachedFileDataSource;
+import org.apache.axiom.om.util.UUIDGenerator;
+
+import javax.activation.DataHandler;
+import javax.mail.MessagingException;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.util.Hashtable;
+
+/**
+ * PartOnFile stores that attachment in a file.
+ * This implementation is used for very large attachments to reduce
+ * the in-memory footprint.
+ * 
+ * The PartOnFile object is created by the PartFactory
+ * @see org.apache.axiom.attachments.impl.PartFactory.
+ */
+public class PartOnFile extends AbstractPart {
+
+    File backingFile;
+    
+    
+    /**
+     * Create a PartOnFile from the specified InputStream
+     * @param headers Hashtable of javax.mail.Headers
+     * @param in1 InputStream containing data
+     * @param in2 InputStream containing data
+     * @param attachmentDir String 
+     */
+    PartOnFile(Hashtable headers, InputStream is1, InputStream is2, String attachmentDir) throws IOException {
+        super(headers);
+        backingFile = createFile(attachmentDir);
+     
+        
+        // Now write the data to the backing file
+        FileOutputStream fos = new FileOutputStream(backingFile);
+        BufferUtils.inputStream2OutputStream(is1, fos);
+        BufferUtils.inputStream2OutputStream(is2, fos);
+        fos.flush();
+        fos.close();
+    }
+    
+    /**
+     * Create a unique file in the designated directory
+     * @param attachmentDir
+     * @return File
+     * @throws IOException
+     */
+    private static File createFile(String attachmentDir) throws IOException {
+        File file = null;
+        File dir = null;
+        if (attachmentDir != null) {
+            dir = new File(attachmentDir);
+            if (!dir.exists()) {
+                dir.mkdirs();
+            }
+        }
+        if (!dir.isDirectory()) {
+            throw new IllegalArgumentException("Given Axis2 Attachment File Cache Location "
+                    + dir + "  should be a directory.");
+        }
+        // Generate unique id.  The UUID generator is used so that we can limit
+        // synchronization with the java random number generator.
+        String id = UUIDGenerator.getUUID();
+        
+        //Replace colons with underscores
+        id = id.replaceAll(":", "_");
+        
+        String fileString = "Axis2" + id + ".att";
+        file = new File(dir, fileString);
+        return file;
+    }
+    
+    /* (non-Javadoc)
+     * @see org.apache.axiom.attachments.impl.AbstractPart#getDataHandler()
+     */
+    public DataHandler getDataHandler() throws MessagingException {
+        CachedFileDataSource dataSource = new CachedFileDataSource(backingFile);
+        dataSource.setContentType(getContentType());
+        return new DataHandler(dataSource);
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.axiom.attachments.impl.AbstractPart#getFileName()
+     */
+    public String getFileName() throws MessagingException {
+        return backingFile.getAbsolutePath();
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.axiom.attachments.impl.AbstractPart#getInputStream()
+     */
+    public InputStream getInputStream() throws IOException, MessagingException {
+        return new FileInputStream(backingFile);
+    }
+    
+    /* (non-Javadoc)
+     * @see org.apache.axiom.attachments.impl.AbstractPart#getSize()
+     */
+    public int getSize() {
+        return (int) backingFile.length();
+    }
+
+}

Added: webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/PartOnMemory.java
URL: http://svn.apache.org/viewvc/webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/PartOnMemory.java?rev=611943&view=auto
==============================================================================
--- webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/PartOnMemory.java (added)
+++ webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/impl/PartOnMemory.java Mon Jan 14 13:36:58 2008
@@ -0,0 +1,140 @@
+/*
+ * 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.axiom.attachments.impl;
+
+import org.apache.axiom.om.OMException;
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+
+import javax.activation.DataHandler;
+import javax.activation.DataSource;
+import javax.mail.MessagingException;
+import javax.mail.internet.MimeUtility;
+
+import java.io.ByteArrayInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.util.Hashtable;
+
+/**
+ * PartOnMemory stores that attachment in memory (in byte arrays)
+ * This implementation is used for smaller attachments to enhance 
+ * performance.
+ * 
+ * The PartOnMemory object is created by the PartFactory
+ * @see org.apache.axiom.attachments.impl.PartFactory.
+ */
+public class PartOnMemory extends AbstractPart {
+
+    private static Log log = LogFactory.getLog(PartOnMemory.class);
+    byte[] bytes;
+    int length;
+    
+    /**
+     * Construct a PartOnMemory
+     * @param headers
+     * @param bytes
+     * @param length (length of data in bytes)
+     */
+    PartOnMemory(Hashtable headers, byte[] bytes, int length) {
+        super(headers);
+        this.bytes =  bytes;
+        this.length = length;
+    }
+
+    public DataHandler getDataHandler() throws MessagingException {
+        DataSource ds = new MyByteArrayDataSource();
+        return new DataHandler(ds);
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.axiom.attachments.impl.AbstractPart#getFileName()
+     */
+    public String getFileName() throws MessagingException {
+        // There is no file name
+        return null;
+    }
+
+    public InputStream getInputStream() throws IOException, MessagingException {
+        return new ByteArrayInputStream(bytes, 0, length);
+    }
+    
+    public int getSize() throws MessagingException {
+        return length;
+    }
+    
+    
+    /**
+     * A DataSource that is backed by the byte[] and 
+     * headers map.
+     */
+    class MyByteArrayDataSource implements DataSource {
+
+        /* (non-Javadoc)
+         * @see javax.activation.DataSource#getContentType()
+         */
+        public String getContentType() {
+            String ct = getHeader("content-type");
+            return (ct == null) ?
+                    "application/octet-stream" :
+                    ct;
+        }
+
+        /* (non-Javadoc)
+         * @see javax.activation.DataSource#getInputStream()
+         */
+        public InputStream getInputStream() throws IOException {
+            InputStream is  = new ByteArrayInputStream(bytes, 0, length);
+            String cte = null;
+            try {
+                cte = getContentTransferEncoding();
+                if(cte != null){
+                    if(log.isDebugEnabled()){
+                        log.debug("Start Decoding stream");
+                    }
+                    return MimeUtility.decode(is, cte);
+
+                }
+            } catch (MessagingException e) {
+                if(log.isDebugEnabled()){
+                    log.debug("Stream Failed decoding");
+                }
+                throw new OMException(e);
+            }
+            return is;
+        }
+
+        /* (non-Javadoc)
+         * @see javax.activation.DataSource#getName()
+         */
+        public String getName() {
+            return "MyByteArrayDataSource";
+        }
+
+        /* (non-Javadoc)
+         * @see javax.activation.DataSource#getOutputStream()
+         */
+        public OutputStream getOutputStream() throws IOException {
+            throw new IOException("Not Supported");
+        }
+        
+    }
+
+}



---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@ws.apache.org
For additional commands, e-mail: commons-dev-help@ws.apache.org