blob: a229af96c16c985166a7a8974138e3a55582ee63 [file] [log] [blame]
/*
* 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 org.apache.axiom.attachments.lifecycle.DataHandlerExt;
import org.apache.axiom.attachments.lifecycle.LifecycleManager;
import org.apache.axiom.attachments.lifecycle.impl.LifecycleManagerImpl;
import org.apache.axiom.blob.Blobs;
import org.apache.axiom.blob.MemoryBlob;
import org.apache.axiom.blob.WritableBlob;
import org.apache.axiom.blob.WritableBlobFactory;
import org.apache.axiom.ext.activation.SizeAwareDataSource;
import org.apache.axiom.mime.ContentType;
import org.apache.axiom.mime.MultipartBody;
import org.apache.axiom.om.OMAttachmentAccessor;
import org.apache.axiom.om.OMException;
import org.apache.axiom.om.impl.MTOMConstants;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.Map;
public class Attachments implements OMAttachmentAccessor {
private final AttachmentsDelegate delegate;
/**
* <code>applicationType</code> used to distinguish between MTOM & SWA If the message is MTOM
* optimised type is application/xop+xml If the message is SWA, type is ??have to find out
*/
private String applicationType;
private LifecycleManager manager;
public LifecycleManager getLifecycleManager() {
if (manager == null) {
manager = new LifecycleManagerImpl();
}
return manager;
}
public void setLifecycleManager(LifecycleManager manager) {
this.manager = manager;
}
/**
* Moves the pointer to the beginning of the first MIME part. Reads till first MIME boundary is
* found or end of stream is reached.
*
* @param inStream
* @param contentTypeString
* @param fileCacheEnable
* @param attachmentRepoDir
* @throws OMException
*/
public Attachments(LifecycleManager manager, InputStream inStream, String contentTypeString,
boolean fileCacheEnable, String attachmentRepoDir,
String fileThreshold) throws OMException {
this(manager, inStream, contentTypeString, fileCacheEnable, attachmentRepoDir, fileThreshold, 0);
}
/**
* Moves the pointer to the beginning of the first MIME part. Reads
* till first MIME boundary is found or end of stream is reached.
*
* @param inStream
* @param contentTypeString
* @param fileCacheEnable
* @param attachmentRepoDir
* @param fileThreshold
* @param contentLength
* @throws OMException
*/
public Attachments(LifecycleManager manager, InputStream inStream, String contentTypeString, boolean fileCacheEnable,
String attachmentRepoDir, String fileThreshold, int contentLength) throws OMException {
this.manager = manager;
final int fileStorageThreshold;
if (fileThreshold != null && (!"".equals(fileThreshold))) {
fileStorageThreshold = Integer.parseInt(fileThreshold);
} else {
fileStorageThreshold = 0;
}
WritableBlobFactory<?> attachmentBlobFactory;
if (fileCacheEnable) {
final WritableBlobFactory<?> tempFileBlobFactory = new LegacyTempFileBlobFactory(this, attachmentRepoDir);
if (fileStorageThreshold > 0) {
attachmentBlobFactory = new WritableBlobFactory<WritableBlob>() {
@Override
public WritableBlob createBlob() {
return Blobs.createOverflowableBlob(fileStorageThreshold, tempFileBlobFactory);
}
};
} else {
attachmentBlobFactory = tempFileBlobFactory;
}
} else {
attachmentBlobFactory = MemoryBlob.FACTORY;
}
delegate = new MultipartBodyAdapter(inStream, contentTypeString, attachmentBlobFactory,
contentLength);
}
/**
* Moves the pointer to the beginning of the first MIME part. Reads till first MIME boundary is
* found or end of stream is reached.
*
* @param inStream
* @param contentTypeString
* @param fileCacheEnable
* @param attachmentRepoDir
* @throws OMException
*/
public Attachments(InputStream inStream, String contentTypeString,
boolean fileCacheEnable, String attachmentRepoDir,
String fileThreshold) throws OMException {
this(null, inStream, contentTypeString, fileCacheEnable, attachmentRepoDir, fileThreshold, 0);
}
/**
* Moves the pointer to the beginning of the first MIME part. Reads
* till first MIME boundary is found or end of stream is reached.
*
* @param inStream
* @param contentTypeString
* @param fileCacheEnable
* @param attachmentRepoDir
* @param fileThreshold
* @param contentLength
* @throws OMException
*/
public Attachments(InputStream inStream, String contentTypeString, boolean fileCacheEnable,
String attachmentRepoDir, String fileThreshold, int contentLength) throws OMException {
this(null, inStream, contentTypeString, fileCacheEnable,
attachmentRepoDir, fileThreshold, contentLength);
}
/**
* Sets file cache to false.
*
* @param inStream
* @param contentTypeString
* @throws OMException
*/
public Attachments(InputStream inStream, String contentTypeString)
throws OMException {
this(null, inStream, contentTypeString, false, null, null);
}
/**
* Use this constructor when instantiating this to store the attachments set programatically
* through the SwA API.
*/
public Attachments() {
delegate = new AttachmentSet();
}
/**
* Identify the type of message (MTOM or SOAP with attachments) represented by this object. Note
* that this method is only meaningful if the instance was created from a stream.
*
* @return One of the {@link MTOMConstants#MTOM_TYPE}, {@link MTOMConstants#SWA_TYPE} or
* {@link MTOMConstants#SWA_TYPE_12} constants.
* @throws OMException
* if the message doesn't have one of the supported types (i.e. is neither MTOM nor
* SOAP with attachments) or if the instance was not created from a stream
*/
public String getAttachmentSpecType() {
if (this.applicationType == null) {
ContentType contentType = delegate.getContentType();
if (contentType == null) {
throw new OMException("Unable to determine the attachment spec type because the " +
"Attachments object doesn't have a known content type");
}
applicationType = contentType.getParameter("type");
if ((MTOMConstants.MTOM_TYPE).equalsIgnoreCase(applicationType)) {
this.applicationType = MTOMConstants.MTOM_TYPE;
} else if ((MTOMConstants.SWA_TYPE).equalsIgnoreCase(applicationType)) {
this.applicationType = MTOMConstants.SWA_TYPE;
} else if ((MTOMConstants.SWA_TYPE_12).equalsIgnoreCase(applicationType)) {
this.applicationType = MTOMConstants.SWA_TYPE_12;
} else {
throw new OMException(
"Invalid Application type. Support available for MTOM & SwA only.");
}
}
return this.applicationType;
}
/**
* Get the {@link DataHandler} object for the MIME part with a given content ID. The returned
* instance MAY implement {@link DataHandlerExt} in which case the caller can use that API to
* stream the content of the part. In addition, the {@link DataSource} linked to the returned
* {@link DataHandler} MAY be of type {@link SizeAwareDataSource} in which case the caller can
* use that interface to determine the size of the MIME part.
*
* @param contentID
* the raw content ID (without the surrounding angle brackets and {@code cid:}
* prefix) of the MIME part
* @return the {@link DataHandler} of the MIME part referred by the content ID or
* <code>null</code> if the MIME part referred by the content ID does not exist
*/
@Override
public DataHandler getDataHandler(String contentID) {
return delegate.getDataHandler(contentID);
}
/**
* Programatically adding an SOAP with Attachments(SwA) Attachment. These attachments will get
* serialized only if SOAP with Attachments is enabled.
*
* @param contentID
* @param dataHandler
*/
public void addDataHandler(String contentID, DataHandler dataHandler) {
delegate.addDataHandler(contentID, dataHandler);
}
/**
* Removes the DataHandler corresponding to the given contenID. If it is not present, then
* trying to find it calling the getNextPart() till the required part is found.
*
* @param blobContentID
*/
public void removeDataHandler(String blobContentID) {
delegate.removeDataHandler(blobContentID);
}
/**
* @deprecated Use {@link #getRootPartInputStream()} instead.
*/
public InputStream getSOAPPartInputStream() throws OMException {
return getRootPartInputStream();
}
/**
* @deprecated Use {@link #getRootPartContentID()} instead.
*/
public String getSOAPPartContentID() {
return getRootPartContentID();
}
/**
* @deprecated Use {@link #getRootPartContentType()} instead.
*/
public String getSOAPPartContentType() {
return getRootPartContentType();
}
/**
* Get an input stream for the root part of the MIME message. The root part is located as
* described in the documentation of the {@link #getRootPartContentID()} method. Note that a new
* stream is returned each time this method is called, i.e. the method does not consume the root
* part. Instead it loads the root part into memory so that it can be read several times.
*
* @return the input stream for the root part
*/
public InputStream getRootPartInputStream() throws OMException {
return delegate.getRootPartInputStream(true);
}
/**
* Get an input stream for the root part of the MIME message. This method is similar to
* {@link #getRootPartInputStream()}, but can be instructed to consume the root part. This
* allows streaming of the root part. If that feature is used, the root part will not be loaded
* into memory unless an attempt is made to access another part of the MIME message, in which
* case the remaining (i.e. unconsumed) content of the root part will be buffered. If the
* feature is not enabled, then this method behaves in the same way as
* {@link #getRootPartInputStream()}.
*
* @param preserve
* <code>true</code> if the content of the root part should be fetched into memory so
* that it can be read several times, <code>false</code> if the root part should be
* consumed
* @return the input stream for the root part
*/
public InputStream getRootPartInputStream(boolean preserve) throws OMException {
return delegate.getRootPartInputStream(preserve);
}
/**
* Get the content ID of the root part of the MIME message. This content ID is determined as
* follows:
* <ul>
* <li>If the content type of the MIME message has a {@code start} parameter, then the content
* ID will be extracted from that parameter.
* <li>Otherwise the content ID of the first MIME part of the MIME message is returned.
* </ul>
*
* @return the content ID of the root part (without the surrounding angle brackets)
*/
public String getRootPartContentID() {
return delegate.getRootPartContentID();
}
/**
* Get the content type of the root part of the MIME message. The root part is located as
* described in the documentation of the {@link #getRootPartContentID()} method.
*
* @return the content type of the root part
* @throws OMException
* if the content type could not be determined
*/
public String getRootPartContentType() {
return delegate.getRootPartContentType();
}
/**
* Stream based access
*
* @return The stream container of type <code>IncomingAttachmentStreams</code>
* @throws IllegalStateException if application has alreadt started using Part's directly
*/
public IncomingAttachmentStreams getIncomingAttachmentStreams()
throws IllegalStateException {
return delegate.getIncomingAttachmentStreams();
}
/**
* Get the content IDs of all MIME parts in the message. This includes the content ID of the
* SOAP part as well as the content IDs of the attachments. Note that if this object has been
* created from a stream, a call to this method will force reading of all MIME parts that
* have not been fetched from the stream yet.
*
* @return an array with the content IDs in order of appearance in the message
*/
public String[] getAllContentIDs() {
Set<String> cids = delegate.getContentIDs(true);
return cids.toArray(new String[cids.size()]);
}
/**
* Get the content IDs of all MIME parts in the message. This includes the content ID of the
* SOAP part as well as the content IDs of the attachments. Note that if this object has been
* created from a stream, a call to this method will force reading of all MIME parts that
* have not been fetched from the stream yet.
*
* @return the set of content IDs
*/
public Set<String> getContentIDSet() {
return delegate.getContentIDs(true);
}
/**
* Get a map of all MIME parts in the message. This includes the SOAP part as well as the
* attachments. Note that if this object has been created from a stream, a call to this
* method will force reading of all MIME parts that have not been fetched from the stream yet.
*
* @return A map of all MIME parts in the message, with content IDs as keys and
* {@link DataHandler} objects as values.
*/
public Map<String,DataHandler> getMap() {
return delegate.getMap();
}
/**
* Get the content IDs of the already loaded MIME parts in the message. This includes the
* content ID of the SOAP part as well as the content IDs of the attachments. If this
* object has been created from a stream, only the content IDs of the MIME parts that
* have already been fetched from the stream are returned. If this is not the desired
* behavior, {@link #getAllContentIDs()} or {@link #getContentIDSet()} should be used
* instead.
*
* @return List of content IDs in order of appearance in message
*/
public List<String> getContentIDList() {
return new ArrayList<String>(delegate.getContentIDs(false));
}
/**
* If the Attachments is backed by an InputStream, then this
* method returns the length of the message contents
* (Length of the entire message - Length of the Transport Headers)
* @return length of message content or -1 if Attachments is not
* backed by an InputStream
*/
public long getContentLength() throws IOException {
return delegate.getContentLength();
}
/**
* @deprecated As of Axiom 1.2.13, this method is no longer supported.
*/
public InputStream getIncomingAttachmentsAsSingleStream() throws IllegalStateException {
throw new UnsupportedOperationException();
}
public MultipartBody getMultipartBody() {
return delegate.getMultipartBody();
}
}