You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ws.apache.org by ve...@apache.org on 2016/04/29 21:25:53 UTC

svn commit: r1741696 - in /webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments: IncomingAttachmentStreams.java MIMEMessage.java MIMEMessageAdapter.java Part.java PartImpl.java PartIterator.java

Author: veithen
Date: Fri Apr 29 19:25:53 2016
New Revision: 1741696

URL: http://svn.apache.org/viewvc?rev=1741696&view=rev
Log:
Reimplement IncomingAttachmentStreams so that it no longer accesses the MIME parser directly.

Added:
    webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/PartIterator.java   (with props)
Modified:
    webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/IncomingAttachmentStreams.java
    webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEMessage.java
    webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEMessageAdapter.java
    webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/Part.java
    webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/PartImpl.java

Modified: webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/IncomingAttachmentStreams.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/IncomingAttachmentStreams.java?rev=1741696&r1=1741695&r2=1741696&view=diff
==============================================================================
--- webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/IncomingAttachmentStreams.java (original)
+++ webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/IncomingAttachmentStreams.java Fri Apr 29 19:25:53 2016
@@ -20,14 +20,10 @@
 package org.apache.axiom.attachments;
 
 import java.io.IOException;
-import java.util.ArrayList;
-import java.util.List;
+import java.util.Iterator;
 
+import org.apache.axiom.mime.Header;
 import org.apache.axiom.om.OMException;
-import org.apache.james.mime4j.MimeException;
-import org.apache.james.mime4j.stream.EntityState;
-import org.apache.james.mime4j.stream.Field;
-import org.apache.james.mime4j.stream.MimeTokenStream;
 
 /**
  * Container for AttachmentStream s. This class provides an SwA like access mechanism, allowing
@@ -35,7 +31,8 @@ import org.apache.james.mime4j.stream.Mi
  * like (stream access), or MTOM like (part/data handler access via blob id), not both.
  */
 public final class IncomingAttachmentStreams {
-    private final MimeTokenStream parser;
+    private final Part rootPart;
+    private final Iterator<Part> partIterator;
 
     /**
      * Boolean indicating weather or not the next stream can be read (next stream cannot be read until
@@ -43,8 +40,9 @@ public final class IncomingAttachmentStr
      */
     private boolean readyToGetNextStream = true;
 
-    IncomingAttachmentStreams(MimeTokenStream parser) {
-        this.parser = parser;
+    IncomingAttachmentStreams(MIMEMessage message) {
+        rootPart = message.getRootPart();
+        partIterator = message.iterator();
     }
 
     /** @return True if the next stream can be read, false otherwise. */
@@ -67,42 +65,31 @@ public final class IncomingAttachmentStr
      * @return The next stream or null if no additional streams are left.
      */
     public IncomingAttachmentInputStream getNextStream() throws OMException {
-        IncomingAttachmentInputStream stream;
-
         if (!readyToGetNextStream) {
             throw new IllegalStateException("nextStreamNotReady");
         }
 
-        try {
-            if (parser.getState() == EntityState.T_BODY) {
-                if (parser.next() != EntityState.T_END_BODYPART) {
-                    throw new IllegalStateException();
-                }
-                parser.next();
-            }
-            
-            if (parser.getState() != EntityState.T_START_BODYPART) {
-                return null;
-            }
-            
-            if (parser.next() != EntityState.T_START_HEADER) {
-                throw new IllegalStateException();
-            }
-            
-            List<Field> fields = new ArrayList<Field>();
-            while (parser.next() == EntityState.T_FIELD) {
-                fields.add(parser.getField());
+        Part part = null;
+        while (part == null && partIterator.hasNext()) {
+            part = partIterator.next();
+            // Skip the root part
+            if (part == rootPart) {
+                part = null;
             }
-            
-            if (parser.next() != EntityState.T_BODY) {
-                throw new IllegalStateException();
+        }
+
+        if (part != null) {
+            IncomingAttachmentInputStream stream;
+
+            try {
+                stream = new IncomingAttachmentInputStream(part.getInputStream(false), this);
+            } catch (IOException ex) {
+                throw new OMException(ex);
             }
-            
-            stream = new IncomingAttachmentInputStream(parser.getInputStream(), this);
     
-            for (Field field : fields) {
-                String name = field.getName();
-                String value = field.getBody();
+            for (Header header : part.getHeaders()) {
+                String name = header.getName();
+                String value = header.getValue();
                 if (IncomingAttachmentInputStream.HEADER_CONTENT_ID.equals(name)
                         || IncomingAttachmentInputStream.HEADER_CONTENT_TYPE.equals(name)
                         || IncomingAttachmentInputStream.HEADER_CONTENT_LOCATION.equals(name)) {
@@ -110,13 +97,11 @@ public final class IncomingAttachmentStr
                 }
                 stream.addHeader(name, value);
             }
-        } catch (MimeException ex) {
-            throw new OMException(ex);
-        } catch (IOException ex) {
-            throw new OMException(ex);
+            
+            readyToGetNextStream = false;
+            return stream;
+        } else {
+            return null;
         }
-
-        readyToGetNextStream = false;
-        return stream;
     }
 }
\ No newline at end of file

Modified: webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEMessage.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEMessage.java?rev=1741696&r1=1741695&r2=1741696&view=diff
==============================================================================
--- webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEMessage.java (original)
+++ webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEMessage.java Fri Apr 29 19:25:53 2016
@@ -23,6 +23,7 @@ import java.io.InputStream;
 import java.text.ParseException;
 import java.util.ArrayList;
 import java.util.Collections;
+import java.util.Iterator;
 import java.util.LinkedHashMap;
 import java.util.List;
 import java.util.Map;
@@ -49,7 +50,7 @@ import org.apache.james.mime4j.stream.Re
  * {@link AttachmentsDelegate} implementation that represents a MIME multipart message read from a
  * stream.
  */
-class MIMEMessage {
+class MIMEMessage implements Iterable<Part> {
     private static final Log log = LogFactory.getLog(MIMEMessage.class);
     
     /** <code>ContentType</code> of the MIME message */
@@ -68,15 +69,6 @@ class MIMEMessage {
      */
     private PartImpl currentPart;
     
-    /** Container to hold streams for direct access */
-    private IncomingAttachmentStreams streams;
-
-    /** <code>boolean</code> Indicating if any streams have been directly requested */
-    private boolean streamsRequested;
-
-    /** <code>boolean</code> Indicating if any data handlers have been directly requested */
-    private boolean partsRequested;
-
     private PartImpl firstPart;
     private PartImpl rootPart;
 
@@ -112,13 +104,6 @@ class MIMEMessage {
                 throw new OMException(ex);
             }
         }
-
-        // Read the root part and cache it
-        getDataHandler(getRootPartContentID());
-
-        // Now reset partsRequested. The root part is a special case which is always 
-        // read beforehand, regardless of request.
-        partsRequested = false;
     }
 
     ContentType getContentType() {
@@ -135,6 +120,13 @@ class MIMEMessage {
         return null;
     }
 
+    PartImpl getFirstPart() {
+        if (firstPart == null) {
+            getNextPart();
+        }
+        return firstPart;
+    }
+
     Part getRootPart() {
         do {
             if (rootPart != null) {
@@ -148,31 +140,13 @@ class MIMEMessage {
     String getRootPartContentID() {
         // to handle the Start parameter not mentioned situation
         if (rootPartContentID == null) {
-            if (partMap.isEmpty()) {
-                getNextPart();
-            }
+            Part firstPart = getFirstPart();
             return firstPart == null ? null : firstPart.getContentID();
         } else {
             return rootPartContentID;
         }
     }
     
-    IncomingAttachmentStreams getIncomingAttachmentStreams() {
-        if (partsRequested) {
-            throw new IllegalStateException(
-                    "The attachments stream can only be accessed once; either by using the IncomingAttachmentStreams class or by getting a " +
-                            "collection of AttachmentPart objects. They cannot both be called within the life time of the same service request.");
-        }
-        
-        streamsRequested = true;
-        
-        if (this.streams == null) {
-            this.streams = new IncomingAttachmentStreams(parser);
-        }
-        
-        return this.streams;
-    }
-
     /**
      * Force reading of all attachments.
      */
@@ -194,18 +168,12 @@ class MIMEMessage {
         return Collections.<String,Part>unmodifiableMap(partMap);
     }
     
-    private PartImpl getNextPart() throws OMException {
-        if (streamsRequested) {
-            throw new IllegalStateException("The attachments stream can only be accessed once; either by using the IncomingAttachmentStreams class or by getting a collection of AttachmentPart objects. They cannot both be called within the life time of the same service request.");
-        }
-        partsRequested = true;
-        
+    PartImpl getNextPart() throws OMException {
         if (currentPart != null) {
             currentPart.fetch();
-            currentPart = null;
         }
         if (parser.getState() == EntityState.T_END_MULTIPART) {
-            return null;
+            currentPart = null;
         } else {
             String partContentID = null;
             boolean isRootPart;
@@ -241,7 +209,13 @@ class MIMEMessage {
                             "Part content ID cannot be blank for non root MIME parts");
                 }
                 
-                currentPart = new PartImpl(isRootPart ? MemoryBlob.FACTORY : attachmentBlobFactory, partContentID, headers, parser);
+                PartImpl part = new PartImpl(this, isRootPart ? MemoryBlob.FACTORY : attachmentBlobFactory, partContentID, headers, parser);
+                if (currentPart == null) {
+                    firstPart = part;
+                } else {
+                    currentPart.setNextPart(part);
+                }
+                currentPart = part;
             } catch (IOException ex) {
                 throw new OMException(ex);
             } catch (MimeException ex) {
@@ -252,9 +226,6 @@ class MIMEMessage {
                 // We only get here if isRootPart is true
                 partContentID = "firstPart_" + UIDGenerator.generateContentId();
             }
-            if (partMap.isEmpty()) {
-                firstPart = currentPart;
-            }
             if (partMap.containsKey(partContentID)) {
                 throw new OMException(
                         "Two MIME parts with the same Content-ID not allowed.");
@@ -263,8 +234,8 @@ class MIMEMessage {
             if (isRootPart) {
                 rootPart = currentPart;
             }
-            return currentPart;
         }
+        return currentPart;
     }
 
     private static void checkParserState(EntityState state, EntityState expected) throws IllegalStateException {
@@ -273,4 +244,9 @@ class MIMEMessage {
                     + expected + ", but got " + state);
         }
     }
+
+    @Override
+    public Iterator<Part> iterator() {
+        return new PartIterator(this);
+    }
 }

Modified: webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEMessageAdapter.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEMessageAdapter.java?rev=1741696&r1=1741695&r2=1741696&view=diff
==============================================================================
--- webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEMessageAdapter.java (original)
+++ webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/MIMEMessageAdapter.java Fri Apr 29 19:25:53 2016
@@ -44,6 +44,15 @@ final class MIMEMessageAdapter extends A
     private final int contentLength;
     private final CountingInputStream filterIS;
 
+    /** <code>boolean</code> Indicating if any streams have been directly requested */
+    private boolean streamsRequested;
+
+    /** <code>boolean</code> Indicating if any data handlers have been directly requested */
+    private boolean partsRequested;
+
+    /** Container to hold streams for direct access */
+    private IncomingAttachmentStreams streams;
+
     MIMEMessageAdapter(InputStream inStream, String contentTypeString,
             WritableBlobFactory<?> attachmentBlobFactory, int contentLength) {
         this.contentLength = contentLength;
@@ -62,6 +71,13 @@ final class MIMEMessageAdapter extends A
         this.message = new MIMEMessage(inStream, contentTypeString, attachmentBlobFactory);
     }
 
+    private void requestParts() {
+        if (streamsRequested) {
+            throw new IllegalStateException("The attachments stream can only be accessed once; either by using the IncomingAttachmentStreams class or by getting a collection of AttachmentPart objects. They cannot both be called within the life time of the same service request.");
+        }
+        partsRequested = true;
+    }
+
     @Override
     ContentType getContentType() {
         return message.getContentType();
@@ -69,6 +85,7 @@ final class MIMEMessageAdapter extends A
 
     @Override
     DataHandler getDataHandler(String contentID) {
+        requestParts();
         DataHandler dh = addedDataHandlers.get(contentID);
         if (dh != null) {
             return dh;
@@ -81,11 +98,13 @@ final class MIMEMessageAdapter extends A
 
     @Override
     void addDataHandler(String contentID, DataHandler dataHandler) {
+        requestParts();
         addedDataHandlers.put(contentID, dataHandler);
     }
 
     @Override
     void removeDataHandler(String blobContentID) {
+        requestParts();
         if (addedDataHandlers.remove(blobContentID) == null) {
             removedDataHandlers.add(blobContentID);
         }
@@ -112,11 +131,25 @@ final class MIMEMessageAdapter extends A
 
     @Override
     IncomingAttachmentStreams getIncomingAttachmentStreams() {
-        return message.getIncomingAttachmentStreams();
+        if (partsRequested) {
+            throw new IllegalStateException(
+                    "The attachments stream can only be accessed once; either by using the IncomingAttachmentStreams class or by getting a " +
+                            "collection of AttachmentPart objects. They cannot both be called within the life time of the same service request.");
+        }
+        
+        streamsRequested = true;
+        
+        if (streams == null) {
+            streams = new IncomingAttachmentStreams(message);
+        }
+        
+        return streams;
     }
 
+
     @Override
     Set<String> getContentIDs(boolean fetchAll) {
+        requestParts();
         Set<String> result = new LinkedHashSet<String>(message.getContentIDs(fetchAll));
         result.removeAll(removedDataHandlers);
         result.addAll(addedDataHandlers.keySet());
@@ -125,6 +158,7 @@ final class MIMEMessageAdapter extends A
 
     @Override
     Map<String,DataHandler> getMap() {
+        requestParts();
         Map<String,DataHandler> result = new LinkedHashMap<String,DataHandler>();
         for (Map.Entry<String,Part> entry : message.getMap().entrySet()) {
             String contentID = entry.getKey();
@@ -141,6 +175,7 @@ final class MIMEMessageAdapter extends A
         if (contentLength > 0) {
             return contentLength;
         } else {
+            requestParts();
             // Ensure all parts are read
             message.fetchAllParts();
             // Now get the count from the filter

Modified: webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/Part.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/Part.java?rev=1741696&r1=1741695&r2=1741696&view=diff
==============================================================================
--- webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/Part.java (original)
+++ webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/Part.java Fri Apr 29 19:25:53 2016
@@ -20,10 +20,12 @@ package org.apache.axiom.attachments;
 
 import java.io.IOException;
 import java.io.InputStream;
+import java.util.List;
 
 import javax.activation.DataHandler;
 
 import org.apache.axiom.blob.Blob;
+import org.apache.axiom.mime.Header;
 
 /**
  * Interface representing a MIME part. A part can be the SOAP part (or more generally the root part
@@ -75,4 +77,6 @@ public interface Part {
     public InputStream getInputStream(boolean preserve) throws IOException;
     
     public void releaseContent() throws IOException;
+    
+    List<Header> getHeaders();
 }

Modified: webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/PartImpl.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/PartImpl.java?rev=1741696&r1=1741695&r2=1741696&view=diff
==============================================================================
--- webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/PartImpl.java (original)
+++ webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/PartImpl.java Fri Apr 29 19:25:53 2016
@@ -68,6 +68,7 @@ final class PartImpl implements Part {
 
     private static final Log log = LogFactory.getLog(PartImpl.class);
     
+    private final MIMEMessage message;
     private final WritableBlobFactory<?> blobFactory;
     
     private final String contentID;
@@ -90,7 +91,10 @@ final class PartImpl implements Part {
     
     private PartInputStream partInputStream;
     
-    PartImpl(WritableBlobFactory<?> blobFactory, String contentID, List<Header> headers, MimeTokenStream parser) {
+    private PartImpl nextPart;
+    
+    PartImpl(MIMEMessage message, WritableBlobFactory<?> blobFactory, String contentID, List<Header> headers, MimeTokenStream parser) {
+        this.message = message;
         this.blobFactory = blobFactory;
         this.contentID = contentID;
         this.headers = headers;
@@ -114,6 +118,10 @@ final class PartImpl implements Part {
         return value;
     }
 
+    public List<Header> getHeaders() {
+        return headers;
+    }
+
     public String getContentID() {
         return contentID;
     }
@@ -263,4 +271,15 @@ final class PartImpl implements Part {
                 content.release();
         }
     }
+    
+    PartImpl getNextPart() {
+        if (nextPart == null) {
+            message.getNextPart();
+        }
+        return nextPart;
+    }
+
+    void setNextPart(PartImpl nextPart) {
+        this.nextPart = nextPart;
+    }
 }

Added: webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/PartIterator.java
URL: http://svn.apache.org/viewvc/webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/PartIterator.java?rev=1741696&view=auto
==============================================================================
--- webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/PartIterator.java (added)
+++ webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/PartIterator.java Fri Apr 29 19:25:53 2016
@@ -0,0 +1,60 @@
+/*
+ * 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;
+
+import java.util.Iterator;
+import java.util.NoSuchElementException;
+
+final class PartIterator implements Iterator<Part> {
+    private final MIMEMessage message;
+    private PartImpl part;
+    private boolean hasNextCalled;
+
+    PartIterator(MIMEMessage message) {
+        this.message = message;
+    }
+
+    @Override
+    public boolean hasNext() {
+        if (!hasNextCalled) {
+            if (part == null) {
+                part = message.getFirstPart();
+            } else {
+                part = part.getNextPart();
+            }
+            hasNextCalled = true;
+        }
+        return part != null;
+    }
+
+    @Override
+    public Part next() {
+        if (hasNext()) {
+            hasNextCalled = false;
+            return part;
+        } else {
+            throw new NoSuchElementException();
+        }
+    }
+
+    @Override
+    public void remove() {
+        throw new UnsupportedOperationException();
+    }
+}

Propchange: webservices/axiom/trunk/axiom-api/src/main/java/org/apache/axiom/attachments/PartIterator.java
------------------------------------------------------------------------------
    svn:eol-style = native