thanks,
dims
On 7/12/07, Thilina Gunarathne <[EMAIL PROTECTED]> wrote:
> Hi,
> Can we have a cleaner patch of the specific changes please... It would
> be really nice if you can revert this and commit the only the changed
> lines without all the formatting changes...
>
> We are on the verge of a release of Axiom and Axis2 (even the RC's
> have gone).. In that case I think we need to be much more careful when
> committing stuff...
>
> thanks,
> Thilina
>
> > Also added a method to the Attachments class to get the attachments in
order.
> AFAIK
> > This can be useful in SWA "raw" situations. In such scenarios the xml does
not have a reference cid
> > to the attachment. Thus the receiver may wish to view the attachments in
the order that they appeared
> > on the wire. One use case is JAX-WS RPC/LIT support with SWA attachments.
> >
> > Modified:
> >
webservices/commons/trunk/modules/axiom/modules/axiom-api/src/main/java/org/apache/axiom/attachments/Attachments.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?view=diff&rev=555379&r1=555378&r2=555379
> >
==============================================================================
> > ---
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
Wed Jul 11 12:51:52 2007
> > @@ -1,529 +1,609 @@
> > -/*
> > - * 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.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.ByteArrayInputStream;
> > -import java.io.IOException;
> > -import java.io.InputStream;
> > -import java.io.PushbackInputStream;
> > -import java.io.UnsupportedEncodingException;
> > -import java.util.Set;
> > -import java.util.TreeMap;
> > -
> > -public class Attachments {
> > -
> > - /** <code>ContentType</code> of the MIME message */
> > - ContentType contentType;
> > -
> > - /** Mime <code>boundary</code> which separates mime parts */
> > - byte[] boundary;
> > -
> > - /**
> > - * <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
> > - */
> > - String applicationType;
> > -
> > - /**
> > - * <code>pushbackInStream</code> stores the reference to the incoming
stream A PushbackStream
> > - * has the ability to "push back" or "unread" one byte.
> > - */
> > - PushbackInputStream pushbackInStream;
> > - int PUSHBACK_SIZE = 1000;
> > -
> > - /**
> > - * <code>attachmentsMap</code> stores the Data Handlers of the already
parsed Mime Body Parts.
> > - * This ordered Map is keyed using the content-ID's.
> > - */
> > - TreeMap attachmentsMap;
> > -
> > - /** <code>partIndex</code>- Number of Mime parts parsed */
> > - int partIndex = 0;
> > -
> > - /** Container to hold streams for direct access */
> > - IncomingAttachmentStreams streams = null;
> > -
> > - /** <code>boolean</code> Indicating if any streams have been directly
requested */
> > - private boolean streamsRequested = false;
> > -
> > - /** <code>boolean</code> Indicating if any data handlers have been
directly requested */
> > - private boolean partsRequested = false;
> > -
> > - /**
> > - * <code>endOfStreamReached</code> flag which is to be set by
MIMEBodyPartStream when MIME
> > - * message terminator is found.
> > - */
> > - private boolean endOfStreamReached;
> > -
> > -
> > - /**
> > - * <code>noStreams</code> flag which is to be set when this class is
instantiated by the SwA API
> > - * to handle programatic added attachements. An InputStream with
attachments is not present at
> > - * that occation.
> > - */
> > - private boolean noStreams = false;
> > -
> > - private String firstPartId;
> > -
> > - private boolean fileCacheEnable;
> > -
> > - private String attachmentRepoDir;
> > -
> > - private int fileStorageThreshold;
> > -
> > - protected static Log log = LogFactory.getLog(Attachments.class);
> > -
> > -
> > - /**
> > - * 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.attachmentRepoDir = attachmentRepoDir;
> > - this.fileCacheEnable = fileCacheEnable;
> > - if (fileThreshold != null && (!"".equals(fileThreshold))) {
> > - this.fileStorageThreshold = Integer.parseInt(fileThreshold);
> > - } else {
> > - this.fileStorageThreshold = 1;
> > - }
> > - attachmentsMap = new TreeMap();
> > - try {
> > - contentType = new ContentType(contentTypeString);
> > - } catch (ParseException e) {
> > - throw new OMException(
> > - "Invalid Content Type Field in the Mime Message"
> > - , e);
> > - }
> > - // REVIEW: This conversion is hard-coded to UTF-8.
> > - // The complete solution is to respect the charset setting of the
message.
> > - // However this may cause problems in BoundaryDelimittedStream and
other
> > - // lower level classes.
> > -
> > - // Boundary always have the prefix "--".
> > - try {
> > - String encoding = contentType.getParameter("charset");
> > - if(encoding == null || encoding.length()==0){
> > - encoding = "UTF-8";
> > - }
> > - this.boundary = ("--" + contentType.getParameter("boundary"))
> > - .getBytes(encoding);
> > - } catch (UnsupportedEncodingException e) {
> > - throw new OMException(e);
> > - }
> > -
> > - // do we need to wrap InputStream from a BufferedInputStream before
> > - // wrapping from PushbackStream
> > - pushbackInStream = new PushbackInputStream(inStream,
> > - PUSHBACK_SIZE);
> > -
> > - // Move the read pointer to the beginning of the first part
> > - // read till the end of first boundary
> > - while (true) {
> > - int value;
> > - try {
> > - value = pushbackInStream.read();
> > - if ((byte) value == boundary[0]) {
> > - int boundaryIndex = 0;
> > - while ((boundaryIndex < boundary.length)
> > - && ((byte) value == boundary[boundaryIndex])) {
> > - value = pushbackInStream.read();
> > - if (value == -1) {
> > - throw new OMException(
> > - "Unexpected End of Stream while searching
for first Mime Boundary");
> > - }
> > - boundaryIndex++;
> > - }
> > - if (boundaryIndex == boundary.length) { // boundary
found
> > - pushbackInStream.read();
> > - break;
> > - }
> > - } else if ((byte) value == -1) {
> > - throw new OMException(
> > - "Mime parts not found. Stream ended while searching
for the boundary");
> > - }
> > - } catch (IOException e1) {
> > - throw new OMException("Stream Error" + e1.toString(), e1);
> > - }
> > - }
> > -
> > - // Read the SOAP part and cache it
> > - getDataHandler(getSOAPPartContentID());
> > -
> > - // Now reset partsRequested. SOAP part is a special case which is
always
> > - // read beforehand, regardless of request.
> > - partsRequested = false;
> > - }
> > -
> > - /**
> > - * Sets file cache to false.
> > - *
> > - * @param inStream
> > - * @param contentTypeString
> > - * @throws OMException
> > - */
> > - public Attachments(InputStream inStream, String contentTypeString)
> > - throws OMException {
> > - this(inStream, contentTypeString, false, null, null);
> > - }
> > -
> > - /**
> > - * Use this constructor when instantiating this to store the
attachments set programatically
> > - * through the SwA API.
> > - */
> > - public Attachments() {
> > - attachmentsMap = new TreeMap();
> > - noStreams = true;
> > - }
> > -
> > - /**
> > - * @return whether Message Type is SOAP with Attachments or MTOM
optimized, by checking the
> > - * application type parameter in the Content Type.
> > - */
> > - public String getAttachmentSpecType() {
> > - if (this.applicationType == null) {
> > - 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;
> > - }
> > -
> > - /**
> > - * Checks whether the MIME part is already parsed by checking the
attachments HashMap. If it is
> > - * not parsed yet then call the getNextPart() till the required part
is found.
> > - *
> > - * @param blobContentID (without the surrounding angle brackets and
"cid:" prefix)
> > - * @return The DataHandler of the mime part referred by the Content-Id
or *null* if the mime
> > - * part referred by the content-id does not exist
> > - */
> > - public DataHandler getDataHandler(String blobContentID) {
> > - DataHandler dataHandler;
> > - if (attachmentsMap.containsKey(blobContentID)) {
> > - dataHandler = (DataHandler) attachmentsMap.get(blobContentID);
> > - return dataHandler;
> > - } else if (!noStreams) {
> > - //This loop will be terminated by the Exceptions thrown if the
Mime
> > - // part searching was not found
> > - while ((dataHandler = this.getNextPartDataHandler()) != null) {
> > - if (attachmentsMap.containsKey(blobContentID)) {
> > - dataHandler = (DataHandler)
attachmentsMap.get(blobContentID);
> > - return dataHandler;
> > - }
> > - }
> > - }
> > - return null;
> > - }
> > -
> > - /**
> > - * 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) {
> > - attachmentsMap.put(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) {
> > - DataHandler dataHandler;
> > - if (attachmentsMap.containsKey(blobContentID)) {
> > - attachmentsMap.remove(blobContentID);
> > - } else if (!noStreams) {
> > - //This loop will be terminated by the Exceptions thrown if the
Mime
> > - // part searching was not found
> > - while ((dataHandler = this.getNextPartDataHandler()) != null) {
> > - if (attachmentsMap.containsKey(blobContentID)) {
> > - attachmentsMap.remove(blobContentID);
> > - }
> > - }
> > - }
> > - }
> > -
> > - /**
> > - * @return the InputStream which includes the SOAP Envelope. It
assumes that the root mime part
> > - * is always pointed by "start" parameter in content-type.
> > - */
> > - public InputStream getSOAPPartInputStream() throws OMException {
> > - DataHandler dh;
> > - if (noStreams) {
> > - throw new OMException("Invalid operation. Attachments are created
programatically.");
> > - }
> > - try {
> > - dh = getDataHandler(getSOAPPartContentID());
> > - if (dh == null) {
> > - throw new OMException(
> > - "Mandatory Root MIME part containing the SOAP Envelope
is missing");
> > - }
> > - return dh.getInputStream();
> > - } catch (IOException e) {
> > - throw new OMException(
> > - "Problem with DataHandler of the Root Mime Part. ", e);
> > - }
> > - }
> > -
> > - /**
> > - * @return the Content-ID of the SOAP part It'll be the value Start
Parameter of Content-Type
> > - * header if given in the Content type of the MIME message.
Else it'll be the content-id
> > - * of the first MIME part of the MIME message
> > - */
> > - public String getSOAPPartContentID() {
> > - String rootContentID = contentType.getParameter("start");
> > -
> > - // to handle the Start parameter not mentioned situation
> > - if (rootContentID == null) {
> > - if (partIndex == 0) {
> > - getNextPartDataHandler();
> > - }
> > - rootContentID = firstPartId;
> > - } else {
> > - rootContentID = rootContentID.trim();
> > -
> > - if ((rootContentID.indexOf("<") > -1)
> > - & (rootContentID.indexOf(">") > -1)) {
> > - rootContentID = rootContentID.substring(1, (rootContentID
> > - .length() - 1));
> > - }
> > - }
> > - // Strips off the "cid" part from content-id
> > - if ("cid".equalsIgnoreCase(rootContentID.substring(0, 3))) {
> > - rootContentID = rootContentID.substring(4);
> > - }
> > - return rootContentID;
> > - }
> > -
> > - public String getSOAPPartContentType() {
> > - if (!noStreams) {
> > - DataHandler soapPart = getDataHandler(getSOAPPartContentID());
> > - return soapPart.getContentType();
> > - } else {
> > - throw new OMException(
> > - "The attachments map was created programatically.
Unsupported operation.");
> > - }
> > - }
> > -
> > - /**
> > - * 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 {
> > - 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.");
> > - }
> > - if (noStreams) {
> > - throw new IllegalStateException(
> > - "The attachments map was created programatically. No
streams are available.");
> > - }
> > -
> > - streamsRequested = true;
> > -
> > - if (this.streams == null) {
> > - BoundaryDelimitedStream boundaryDelimitedStream =
> > - new BoundaryDelimitedStream(pushbackInStream,
> > - boundary, 1024);
> > -
> > - this.streams = new
MultipartAttachmentStreams(boundaryDelimitedStream);
> > - }
> > -
> > - return this.streams;
> > - }
> > -
> > - public String[] getAllContentIDs() {
> > - Set keys = getContentIDSet();
> > - return (String[]) keys.toArray(new String[keys.size()]);
> > - }
> > -
> > - public Set getContentIDSet() {
> > - DataHandler dataHandler;
> > - while (!noStreams) {
> > - dataHandler = this.getNextPartDataHandler();
> > - if (dataHandler == null) {
> > - break;
> > - }
> > - }
> > - return attachmentsMap.keySet();
> > - }
> > -
> > - /**
> > - * endOfStreamReached will be set to true if the message ended in MIME Style
having "--" suffix
> > - * with the last mime boundary
> > - *
> > - * @param value
> > - */
> > - protected void setEndOfStream(boolean value) {
> > - this.endOfStreamReached = value;
> > - }
> > -
> > - /**
> > - * @return the Next valid MIME part + store the Part in the Parts List
> > - * @throws OMException throw if content id is null or if two MIME
parts contain the same
> > - * content-ID & the exceptions throws by getPart()
> > - */
> > - private DataHandler getNextPartDataHandler() throws OMException {
> > - if (endOfStreamReached) {
> > - return null;
> > - }
> > - Part nextPart;
> > - nextPart = getPart();
> > - if (nextPart == null) {
> > - return null;
> > - } else
> > - try {
> > - if (nextPart.getSize() > 0) {
> > - String partContentID;
> > - try {
> > - partContentID = nextPart.getContentID();
> > -
> > - if (partContentID == null & partIndex == 1) {
> > - String id = "firstPart_" +
UUIDGenerator.getUUID();
> > - attachmentsMap.put(id,
nextPart.getDataHandler());
> > - firstPartId = id;
> > - return nextPart.getDataHandler();
> > - }
> > - if (partContentID == null) {
> > - throw new OMException(
> > - "Part content ID cannot be blank for non
root MIME parts");
> > - }
> > - if ((partContentID.indexOf("<") > -1)
> > - & (partContentID.indexOf(">") > -1)) {
> > - partContentID = partContentID.substring(1,
(partContentID
> > - .length() - 1));
> > -
> > - } else if (partIndex == 1) {
> > - firstPartId = partContentID;
> > - }
> > - if (attachmentsMap.containsKey(partContentID)) {
> > - throw new OMException(
> > - "Two MIME parts with the same Content-ID
not allowed.");
> > - }
> > - attachmentsMap.put(partContentID,
nextPart.getDataHandler());
> > - return nextPart.getDataHandler();
> > - } catch (MessagingException e) {
> > - throw new OMException("Error reading Content-ID from
the Part."
> > - + e);
> > - }
> > - } // This will take care if stream ended without having
MIME
> > - // message terminator
> > - else {
> > - return null;
> > - }
> > - } catch (MessagingException e) {
> > - throw new OMException(e);
> > - }
> > - }
> > -
> > - /**
> > - * @return This will return the next available MIME part in the stream.
> > - * @throws OMException if Stream ends while reading the next part...
> > - */
> > - private Part getPart() 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;
> > -
> > - Part part;
> > -
> > - try {
> > - if (fileCacheEnable) {
> > - try {
> > - MIMEBodyPartInputStream partStream;
> > - byte[] buffer = new byte[fileStorageThreshold];
> > - partStream = new
MIMEBodyPartInputStream(pushbackInStream,
> > - boundary,
this, PUSHBACK_SIZE);
> > - int count = 0;
> > - do {
> > - int len;
> > - int off = 0;
> > - int rem = fileStorageThreshold;
> > - while ((len = partStream.read(buffer, off, rem)) >
0) {
> > - off = off + len;
> > - rem = rem - len;
> > - }
> > - count += off;
> > - } while (partStream.available() > 0);
> > -
> > - if (count == fileStorageThreshold) {
> > - PushbackFilePartInputStream filePartStream =
> > - new PushbackFilePartInputStream(
> > - partStream, buffer);
> > - part = new PartOnFile(filePartStream,
attachmentRepoDir);
> > - } else {
> > - ByteArrayInputStream byteArrayInStream = new
ByteArrayInputStream(buffer,
> > -
0, count);
> > - part = new PartOnMemory(byteArrayInStream);
> > - }
> > - } 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);
> > - }
> > - partIndex++;
> > - return part;
> > - }
> > +/*
> > + * 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.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.ByteArrayInputStream;
> > +import java.io.IOException;
> > +import java.io.InputStream;
> > +import java.io.PushbackInputStream;
> > +import java.io.UnsupportedEncodingException;
> > +import java.util.ArrayList;
> > +import java.util.List;
> > +import java.util.Set;
> > +import java.util.TreeMap;
> > +
> > +public class Attachments {
> > +
> > + /** <code>ContentType</code> of the MIME message */
> > + ContentType contentType;
> > +
> > + int contentLength; // Content Length
> > +
> > + /** Mime <code>boundary</code> which separates mime parts */
> > + byte[] boundary;
> > +
> > + /**
> > + * <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
> > + */
> > + String applicationType;
> > +
> > + /**
> > + * <code>pushbackInStream</code> stores the reference to the incoming
stream A PushbackStream
> > + * has the ability to "push back" or "unread" one byte.
> > + */
> > + PushbackInputStream pushbackInStream;
> > + int PUSHBACK_SIZE = 1000;
> > +
> > + /**
> > + * <code>attachmentsMap</code> stores the Data Handlers of the already
parsed Mime Body Parts.
> > + * This ordered Map is keyed using the content-ID's.
> > + */
> > + TreeMap attachmentsMap;
> > +
> > + /**
> > + * <code>cids</code> stores the content ids in the order that the
attachments
> > + * occur in the message
> > + */
> > + ArrayList cids = new ArrayList();
> > +
> > + /** <code>partIndex</code>- Number of Mime parts parsed */
> > + int partIndex = 0;
> > +
> > + /** Container to hold streams for direct access */
> > + IncomingAttachmentStreams streams = null;
> > +
> > + /** <code>boolean</code> Indicating if any streams have been directly
requested */
> > + private boolean streamsRequested = false;
> > +
> > + /** <code>boolean</code> Indicating if any data handlers have been
directly requested */
> > + private boolean partsRequested = false;
> > +
> > + /**
> > + * <code>endOfStreamReached</code> flag which is to be set by
MIMEBodyPartStream when MIME
> > + * message terminator is found.
> > + */
> > + private boolean endOfStreamReached;
> > +
> > +
> > + /**
> > + * <code>noStreams</code> flag which is to be set when this class is
instantiated by the SwA API
> > + * to handle programatic added attachements. An InputStream with
attachments is not present at
> > + * that occation.
> > + */
> > + private boolean noStreams = false;
> > +
> > + private String firstPartId;
> > +
> > + private boolean fileCacheEnable;
> > +
> > + private String attachmentRepoDir;
> > +
> > + private int fileStorageThreshold;
> > +
> > + protected static Log log = LogFactory.getLog(Attachments.class);
> > +
> > +
> > + /**
> > + * 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(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.contentLength = contentLength;
> > + this.attachmentRepoDir = attachmentRepoDir;
> > + this.fileCacheEnable = fileCacheEnable;
> > + if (fileThreshold != null && (!"".equals(fileThreshold))) {
> > + this.fileStorageThreshold = Integer.parseInt(fileThreshold);
> > + } else {
> > + this.fileStorageThreshold = 1;
> > + }
> > + attachmentsMap = new TreeMap();
> > + try {
> > + contentType = new ContentType(contentTypeString);
> > + } catch (ParseException e) {
> > + throw new OMException(
> > + "Invalid Content Type Field in the Mime Message"
> > + , e);
> > + }
> > + // REVIEW: This conversion is hard-coded to UTF-8.
> > + // The complete solution is to respect the charset setting of the
message.
> > + // However this may cause problems in BoundaryDelimittedStream and
other
> > + // lower level classes.
> > +
> > + // Boundary always have the prefix "--".
> > + try {
> > + String encoding = contentType.getParameter("charset");
> > + if(encoding == null || encoding.length()==0){
> > + encoding = "UTF-8";
> > + }
> > + this.boundary = ("--" + contentType.getParameter("boundary"))
> > + .getBytes(encoding);
> > + } catch (UnsupportedEncodingException e) {
> > + throw new OMException(e);
> > + }
> > +
> > + // do we need to wrap InputStream from a BufferedInputStream before
> > + // wrapping from PushbackStream
> > + pushbackInStream = new PushbackInputStream(inStream,
> > + PUSHBACK_SIZE);
> > +
> > + // Move the read pointer to the beginning of the first part
> > + // read till the end of first boundary
> > + while (true) {
> > + int value;
> > + try {
> > + value = pushbackInStream.read();
> > + if ((byte) value == boundary[0]) {
> > + int boundaryIndex = 0;
> > + while ((boundaryIndex < boundary.length)
> > + && ((byte) value == boundary[boundaryIndex])) {
> > + value = pushbackInStream.read();
> > + if (value == -1) {
> > + throw new OMException(
> > + "Unexpected End of Stream while searching
for first Mime Boundary");
> > + }
> > + boundaryIndex++;
> > + }
> > + if (boundaryIndex == boundary.length) { // boundary
found
> > + pushbackInStream.read();
> > + break;
> > + }
> > + } else if ((byte) value == -1) {
> > + throw new OMException(
> > + "Mime parts not found. Stream ended while searching
for the boundary");
> > + }
> > + } catch (IOException e1) {
> > + throw new OMException("Stream Error" + e1.toString(), e1);
> > + }
> > + }
> > +
> > + // Read the SOAP part and cache it
> > + getDataHandler(getSOAPPartContentID());
> > +
> > + // Now reset partsRequested. SOAP part is a special case which is
always
> > + // read beforehand, regardless of request.
> > + partsRequested = false;
> > + }
> > +
> > + /**
> > + * Sets file cache to false.
> > + *
> > + * @param inStream
> > + * @param contentTypeString
> > + * @throws OMException
> > + */
> > + public Attachments(InputStream inStream, String contentTypeString)
> > + throws OMException {
> > + this(inStream, contentTypeString, false, null, null);
> > + }
> > +
> > + /**
> > + * Use this constructor when instantiating this to store the
attachments set programatically
> > + * through the SwA API.
> > + */
> > + public Attachments() {
> > + attachmentsMap = new TreeMap();
> > + noStreams = true;
> > + }
> > +
> > + /**
> > + * @return whether Message Type is SOAP with Attachments or MTOM
optimized, by checking the
> > + * application type parameter in the Content Type.
> > + */
> > + public String getAttachmentSpecType() {
> > + if (this.applicationType == null) {
> > + 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;
> > + }
> > +
> > + /**
> > + * Checks whether the MIME part is already parsed by checking the
attachments HashMap. If it is
> > + * not parsed yet then call the getNextPart() till the required part
is found.
> > + *
> > + * @param blobContentID (without the surrounding angle brackets and
"cid:" prefix)
> > + * @return The DataHandler of the mime part referred by the Content-Id
or *null* if the mime
> > + * part referred by the content-id does not exist
> > + */
> > + public DataHandler getDataHandler(String blobContentID) {
> > + DataHandler dataHandler;
> > + if (attachmentsMap.containsKey(blobContentID)) {
> > + dataHandler = (DataHandler) attachmentsMap.get(blobContentID);
> > + return dataHandler;
> > + } else if (!noStreams) {
> > + //This loop will be terminated by the Exceptions thrown if the
Mime
> > + // part searching was not found
> > + while ((dataHandler = this.getNextPartDataHandler()) != null) {
> > + if (attachmentsMap.containsKey(blobContentID)) {
> > + dataHandler = (DataHandler)
attachmentsMap.get(blobContentID);
> > + return dataHandler;
> > + }
> > + }
> > + }
> > + return null;
> > + }
> > +
> > + /**
> > + * 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) {
> > + attachmentsMap.put(contentID, dataHandler);
> > + if (!cids.contains(contentID)) {
> > + cids.add(contentID);
> > + }
> > + }
> > +
> > + /**
> > + * 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) {
> > + DataHandler dataHandler;
> > + if (attachmentsMap.containsKey(blobContentID)) {
> > + attachmentsMap.remove(blobContentID);
> > + } else if (!noStreams) {
> > + //This loop will be terminated by the Exceptions thrown if the
Mime
> > + // part searching was not found
> > + while ((dataHandler = this.getNextPartDataHandler()) != null) {
> > + if (attachmentsMap.containsKey(blobContentID)) {
> > + attachmentsMap.remove(blobContentID);
> > + }
> > + }
> > + }
> > + if (!cids.contains(blobContentID)) {
> > + cids.remove(blobContentID);
> > + }
> > + }
> > +
> > + /**
> > + * @return the InputStream which includes the SOAP Envelope. It
assumes that the root mime part
> > + * is always pointed by "start" parameter in content-type.
> > + */
> > + public InputStream getSOAPPartInputStream() throws OMException {
> > + DataHandler dh;
> > + if (noStreams) {
> > + throw new OMException("Invalid operation. Attachments are created
programatically.");
> > + }
> > + try {
> > + dh = getDataHandler(getSOAPPartContentID());
> > + if (dh == null) {
> > + throw new OMException(
> > + "Mandatory Root MIME part containing the SOAP Envelope
is missing");
> > + }
> > + return dh.getInputStream();
> > + } catch (IOException e) {
> > + throw new OMException(
> > + "Problem with DataHandler of the Root Mime Part. ", e);
> > + }
> > + }
> > +
> > + /**
> > + * @return the Content-ID of the SOAP part It'll be the value Start
Parameter of Content-Type
> > + * header if given in the Content type of the MIME message.
Else it'll be the content-id
> > + * of the first MIME part of the MIME message
> > + */
> > + public String getSOAPPartContentID() {
> > + String rootContentID = contentType.getParameter("start");
> > +
> > + // to handle the Start parameter not mentioned situation
> > + if (rootContentID == null) {
> > + if (partIndex == 0) {
> > + getNextPartDataHandler();
> > + }
> > + rootContentID = firstPartId;
> > + } else {
> > + rootContentID = rootContentID.trim();
> > +
> > + if ((rootContentID.indexOf("<") > -1)
> > + & (rootContentID.indexOf(">") > -1)) {
> > + rootContentID = rootContentID.substring(1, (rootContentID
> > + .length() - 1));
> > + }
> > + }
> > + // Strips off the "cid" part from content-id
> > + if ("cid".equalsIgnoreCase(rootContentID.substring(0, 3))) {
> > + rootContentID = rootContentID.substring(4);
> > + }
> > + return rootContentID;
> > + }
> > +
> > + public String getSOAPPartContentType() {
> > + if (!noStreams) {
> > + DataHandler soapPart = getDataHandler(getSOAPPartContentID());
> > + return soapPart.getContentType();
> > + } else {
> > + throw new OMException(
> > + "The attachments map was created programatically.
Unsupported operation.");
> > + }
> > + }
> > +
> > + /**
> > + * 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 {
> > + 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.");
> > + }
> > + if (noStreams) {
> > + throw new IllegalStateException(
> > + "The attachments map was created programatically. No
streams are available.");
> > + }
> > +
> > + streamsRequested = true;
> > +
> > + if (this.streams == null) {
> > + BoundaryDelimitedStream boundaryDelimitedStream =
> > + new BoundaryDelimitedStream(pushbackInStream,
> > + boundary, 1024);
> > +
> > + this.streams = new
MultipartAttachmentStreams(boundaryDelimitedStream);
> > + }
> > +
> > + return this.streams;
> > + }
> > +
> > + public String[] getAllContentIDs() {
> > + Set keys = getContentIDSet();
> > + return (String[]) keys.toArray(new String[keys.size()]);
> > + }
> > +
> > + public Set getContentIDSet() {
> > + DataHandler dataHandler;
> > + while (!noStreams) {
> > + dataHandler = this.getNextPartDataHandler();
> > + if (dataHandler == null) {
> > + break;
> > + }
> > + }
> > + return attachmentsMap.keySet();
> > + }
> > +
> > + /**
> > + * @return List of content ids in order of appearance in message
> > + */
> > + public List getContentIDList() {
> > + return cids;
> > + }
> > +
> > + /**
> > + * endOfStreamReached will be set to true if the message ended in MIME Style
having "--" suffix
> > + * with the last mime boundary
> > + *
> > + * @param value
> > + */
> > + protected void setEndOfStream(boolean value) {
> > + this.endOfStreamReached = value;
> > + }
> > +
> > + /**
> > + * @return the Next valid MIME part + store the Part in the Parts List
> > + * @throws OMException throw if content id is null or if two MIME
parts contain the same
> > + * content-ID & the exceptions throws by getPart()
> > + */
> > + private DataHandler getNextPartDataHandler() throws OMException {
> > + if (endOfStreamReached) {
> > + return null;
> > + }
> > + Part nextPart;
> > + nextPart = getPart();
> > + if (nextPart == null) {
> > + return null;
> > + } else
> > + try {
> > + if (nextPart.getSize() > 0) {
> > + String partContentID;
> > + try {
> > + partContentID = nextPart.getContentID();
> > +
> > + if (partContentID == null & partIndex == 1) {
> > + String id = "firstPart_" +
UUIDGenerator.getUUID();
> > + firstPartId = id;
> > + addDataHandler(id, nextPart.getDataHandler());
> > + return nextPart.getDataHandler();
> > + }
> > + if (partContentID == null) {
> > + throw new OMException(
> > + "Part content ID cannot be blank for non
root MIME parts");
> > + }
> > + if ((partContentID.indexOf("<") > -1)
> > + & (partContentID.indexOf(">") > -1)) {
> > + partContentID = partContentID.substring(1,
(partContentID
> > + .length() - 1));
> > +
> > + } else if (partIndex == 1) {
> > + firstPartId = partContentID;
> > + }
> > + if (attachmentsMap.containsKey(partContentID)) {
> > + throw new OMException(
> > + "Two MIME parts with the same Content-ID
not allowed.");
> > + }
> > + addDataHandler(partContentID,
nextPart.getDataHandler());
> > + return nextPart.getDataHandler();
> > + } catch (MessagingException e) {
> > + throw new OMException("Error reading Content-ID from
the Part."
> > + + e);
> > + }
> > + } // This will take care if stream ended without having
MIME
> > + // message terminator
> > + else {
> > + return null;
> > + }
> > + } catch (MessagingException e) {
> > + throw new OMException(e);
> > + }
> > + }
> > +
> > + /**
> > + * @return This will return the next available MIME part in the stream.
> > + * @throws OMException if Stream ends while reading the next part...
> > + */
> > + private Part getPart() 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;
> > +
> > + Part part;
> > +
> > + try {
> > + if (fileCacheEnable) {
> > + try {
> > + if (contentLength != 0 &&
> > + contentLength <= fileStorageThreshold) {
> > + // Since the content-length is less than the
threshold, we can safely
> > + // store it in memory.
> > + if (log.isDebugEnabled()) {
> > + log.debug("Creating an Attachment Part (in
memory)");
> > + }
> > + MIMEBodyPartInputStream partStream =
> > + new MIMEBodyPartInputStream(pushbackInStream,
> > + boundary,
> > + this,
> > + PUSHBACK_SIZE);
> > + part = new PartOnMemory(partStream);
> > + } else if (contentLength != 0 &&
> > + contentLength > fileStorageThreshold * 2) {
> > + if (log.isDebugEnabled()) {
> > + log.debug("Creating an Attachment Part (in a temporary file
in " + attachmentRepoDir + ")");
> > + }
> > + // The content-length is much bigger than the
threshold, then always
> > + // store the attachments in a file. This prevents
unnecessary buffering.
> > + // REVIEW Arbitrary heuristic. Does this need to
be fine-tuned.
> > + MIMEBodyPartInputStream partStream =
> > + new MIMEBodyPartInputStream(pushbackInStream,
> > + boundary,
> > + this,
> > + PUSHBACK_SIZE);
> > + PushbackFilePartInputStream filePartStream =
> > + new PushbackFilePartInputStream(partStream,
new byte[0]);
> > + part = new PartOnFile(filePartStream,
attachmentRepoDir);
> > +
> > + } else {
> > + if (log.isDebugEnabled()) {
> > + log.debug("Buffering attachment part to determine
if it should be stored in memory");
> > + }
> > + // 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;
> > + byte[] buffer = new byte[fileStorageThreshold];
> > + partStream =
> > + new MIMEBodyPartInputStream(pushbackInStream,
> > + boundary,
> > + this,
> > + PUSHBACK_SIZE);
> > + int count = 0;
> > + int value;
> > + count = partStream.read(buffer);
> > +
> > + if (count == fileStorageThreshold) {
> > + if (log.isDebugEnabled()) {
> > + log.debug("The calculated attachment size is " +
count + ". Storing Part in file.");
> > + }
> > + PushbackFilePartInputStream filePartStream =
> > + new
PushbackFilePartInputStream(partStream, buffer);
> > + part = new PartOnFile(filePartStream,
attachmentRepoDir);
> > + } else {
> > + if (log.isDebugEnabled()) {
> > + log.debug("The calculated attachment size is " +
count + ". Storing Part in memory.");
> > + }
> > + ByteArrayInputStream byteArrayInStream =
> > + new ByteArrayInputStream(buffer, 0, count);
> > + part = new PartOnMemory(byteArrayInStream);
> > + }
> > + }
> > + } 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);
> > + }
> > + partIndex++;
> > + return part;
> > + }
> > }
> >
> >
> >
> > ---------------------------------------------------------------------
> > To unsubscribe, e-mail: [EMAIL PROTECTED]
> > For additional commands, e-mail: [EMAIL PROTECTED]
> >
> >
>
>
> --
> Thilina Gunarathne - http://www.wso2.com - http://thilinag.blogspot.com
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: [EMAIL PROTECTED]
> For additional commands, e-mail: [EMAIL PROTECTED]
>
>
--
Davanum Srinivas :: http://davanum.wordpress.com
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]