All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.axiom.mime.PartImpl Maven / Gradle / Ivy

There is a newer version: 5.0.22
Show newest version
/*
 * 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.mime;

import org.apache.axiom.blob.Blob;
import org.apache.axiom.blob.OverflowableBlob;
import org.apache.axiom.blob.WritableBlob;
import org.apache.axiom.blob.WritableBlobFactory;
import org.apache.axiom.ext.io.StreamCopyException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.james.mime4j.MimeException;
import org.apache.james.mime4j.stream.EntityState;
import org.apache.james.mime4j.stream.MimeTokenStream;

import javax.activation.DataHandler;

import java.io.IOException;
import java.io.InputStream;
import java.text.ParseException;
import java.util.Collections;
import java.util.List;

/**
 * Actual implementation of the {@link Part} interface.
 */
final class PartImpl implements Part {
    /**
     * The part has not been read yet. In this case the parser is in state
     * {@link EntityState#T_BODY}.
     */
    private static final int STATE_UNREAD = 0;
    
    /**
     * The part has been read into a memory or file based buffer.
     */
    private static final int STATE_BUFFERED = 1;
    
    /**
     * The part content is being streamed, i.a. the application code consumes the part content
     * without buffering.
     */
    private static final int STATE_STREAMING = 2;
    
    /**
     * The part content has been discarded and can no longer be read. This state is reached either
     * when the content has been streamed or when it is discarded explicitly after being buffered.
     */
    private static final int STATE_DISCARDED = 3;

    private static final Log log = LogFactory.getLog(PartImpl.class);
    
    private final MultipartBody message;
    private final WritableBlobFactory blobFactory;
    
    private final String contentID;
    private final List
headers; private ContentType contentType; private int state = STATE_UNREAD; /** * The MIME parser from which the content of this part is read. This is only set if the state is * {@link #STATE_UNREAD} or {@link #STATE_STREAMING}. */ private MimeTokenStream parser; /** * The content of this part. This is only set if the state is {@link #STATE_BUFFERED}. */ private WritableBlob content; private DataHandler dataHandler; private PartInputStream partInputStream; private PartImpl nextPart; PartImpl(MultipartBody message, WritableBlobFactory blobFactory, String contentID, List
headers, MimeTokenStream parser) { this.message = message; this.blobFactory = blobFactory; this.contentID = contentID; this.headers = headers; this.parser = parser; } @Override public String getHeader(String name) { String value = null; for (int i=0, l=headers.size(); i getHeaders() { return Collections.unmodifiableList(headers); } @Override public String getContentID() { return contentID; } @Override public ContentType getContentType() { if (contentType == null) { try { contentType = new ContentType(getHeader("content-type")); } catch (ParseException ex) { throw new MIMEException(ex); } } return contentType; } @Override public DataHandler getDataHandler() { if (dataHandler == null) { dataHandler = message.getDataHandlerFactory().createDataHandler(this); } return dataHandler; } private WritableBlob getContent() { switch (state) { case STATE_UNREAD: fetch(); // Fall through case STATE_BUFFERED: return content; default: throw new IllegalStateException("The content of the MIME part has already been consumed"); } } @Override public Blob getBlob() { WritableBlob blob = getContent(); if (blob instanceof OverflowableBlob) { WritableBlob overflowBlob = ((OverflowableBlob)blob).getOverflowBlob(); if (overflowBlob != null) { blob = overflowBlob; } } return blob; } private static void checkParserState(EntityState state, EntityState expected) throws IllegalStateException { if (expected != state) { throw new IllegalStateException("Internal error: expected parser to be in state " + expected + ", but got " + state); } } private InputStream getDecodedInputStream() { InputStream in = parser.getDecodedInputStream(); if (log.isDebugEnabled()) { in = new DebugInputStream(in, log); } return in; } public void fetch() { switch (state) { case STATE_UNREAD: checkParserState(parser.getState(), EntityState.T_BODY); content = blobFactory.createBlob(); if (log.isDebugEnabled()) { log.debug("Using blob of type " + content.getClass().getName()); } try { content.readFrom(getDecodedInputStream()); } catch (StreamCopyException ex) { if (ex.getOperation() == StreamCopyException.READ) { throw new MIMEException("Failed to fetch the MIME part content", ex.getCause()); } else { throw new MIMEException("Failed to write the MIME part content to temporary storage", ex.getCause()); } } moveToNextPart(); state = STATE_BUFFERED; break; case STATE_STREAMING: // If the stream is still open, buffer the remaining content try { partInputStream.detach(); } catch (IOException ex) { throw new MIMEException(ex); } partInputStream = null; moveToNextPart(); state = STATE_DISCARDED; } } private void moveToNextPart() { try { checkParserState(parser.next(), EntityState.T_END_BODYPART); EntityState state = parser.next(); if (state == EntityState.T_EPILOGUE) { while (parser.next() != EntityState.T_END_MULTIPART) { // Just loop } } else if (state != EntityState.T_START_BODYPART && state != EntityState.T_END_MULTIPART) { throw new IllegalStateException("Internal error: unexpected parser state " + state); } } catch (IOException ex) { throw new MIMEException(ex); } catch (MimeException ex) { throw new MIMEException(ex); } parser = null; } @Override public InputStream getInputStream(boolean preserve) { if (!preserve && state == STATE_UNREAD) { checkParserState(parser.getState(), EntityState.T_BODY); state = STATE_STREAMING; partInputStream = new PartInputStream(getDecodedInputStream(), blobFactory); return partInputStream; } else { WritableBlob content = getContent(); try { if (preserve) { return content.getInputStream(); } else { return new PartInputStream(content); } } catch (IOException ex) { throw new MIMEException("Failed to retrieve part content from blob", ex); } } } @Override public void discard() { try { switch (state) { case STATE_UNREAD: EntityState parserState; do { parserState = parser.next(); } while (parserState != EntityState.T_START_BODYPART && parserState != EntityState.T_END_MULTIPART); state = STATE_DISCARDED; break; case STATE_BUFFERED: content.release(); } } catch (MimeException ex) { throw new MIMEException(ex); } catch (IOException ex) { throw new MIMEException(ex); } } PartImpl getNextPart() { if (nextPart == null) { message.getNextPart(); } return nextPart; } void setNextPart(PartImpl nextPart) { this.nextPart = nextPart; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy