/* * Copyright 2001-2004 The Apache Software Foundation. * * Licensed 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.axis.attachments; import org.apache.axis.Part; import org.apache.axis.components.logger.LogFactory; import org.apache.axis.components.image.ImageIOFactory; import org.apache.axis.transport.http.HTTPConstants; import org.apache.axis.utils.Messages; import org.apache.axis.utils.SessionUtils; import org.apache.axis.utils.IOUtils; import org.apache.commons.logging.Log; import javax.activation.DataHandler; import javax.xml.soap.SOAPException; import javax.xml.transform.stream.StreamSource; import java.util.Iterator; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.InputStream; /** * An attachment part. * * */ public class AttachmentPart extends javax.xml.soap.AttachmentPart implements Part { /** Field log */ protected static Log log = LogFactory.getLog(AttachmentPart.class.getName()); /** * The data handler. *
* TODO: make private?
* */
javax.activation.DataHandler datahandler = null;
/** Field mimeHeaders. */
private javax.xml.soap.MimeHeaders mimeHeaders =
new javax.xml.soap.MimeHeaders();
private Object contentObject;
/**
* The name of a file used to store the data.
*/
private String attachmentFile;
/**
* Bulds a new AttachmentPart
.
*/
public AttachmentPart() {
setMimeHeader(HTTPConstants.HEADER_CONTENT_ID, SessionUtils.generateSessionId());
}
/**
* Bulds a new AttachmentPart
with a DataHandler
.
*
* @param dh the DataHandler
*/
public AttachmentPart(javax.activation.DataHandler dh) {
setMimeHeader(HTTPConstants.HEADER_CONTENT_ID,
SessionUtils.generateSessionId());
datahandler = dh;
if(dh != null) {
setMimeHeader(HTTPConstants.HEADER_CONTENT_TYPE, dh.getContentType());
javax.activation.DataSource ds = dh.getDataSource();
if (ds instanceof ManagedMemoryDataSource) {
extractFilename((ManagedMemoryDataSource)ds); //and get the filename if appropriate
}
}
}
// fixme: be aware, this may never be called
/**
* On death, we clean up our file.
*
* @throws Throwable if anything went wrong during finalization
*/
protected void finalize() throws Throwable {
dispose();
}
/**
* Get the data handler.
*
* @return the activation DataHandler
*/
public javax.activation.DataHandler getActivationDataHandler() {
return datahandler;
}
/**
* getContentType
*
* @return content type
*/
public String getContentType() {
return getFirstMimeHeader(HTTPConstants.HEADER_CONTENT_TYPE);
}
/**
* Add the specified MIME header, as per JAXM.
*
* @param header
* @param value
*/
public void addMimeHeader(String header, String value) {
mimeHeaders.addHeader(header, value);
}
/**
* Get the specified MIME header.
*
* @param header
*
* @return
*/
public String getFirstMimeHeader(String header) {
String[] values = mimeHeaders.getHeader(header.toLowerCase());
if ((values != null) && (values.length > 0)) {
return values[0];
}
return null;
}
/**
* check if this Part's mimeheaders matches the one passed in.
* TODO: Am not sure about the logic.
*
* @param headers the MimeHeaders
to check
* @return true if all header name, values in headers
are
* found, false otherwise
*/
public boolean matches(javax.xml.soap.MimeHeaders headers) {
for (Iterator i = headers.getAllHeaders(); i.hasNext();) {
javax.xml.soap.MimeHeader hdr = (javax.xml.soap.MimeHeader) i.next();
String values[] = mimeHeaders.getHeader(hdr.getName());
boolean found = false;
if (values != null) {
for (int j = 0; j < values.length; j++) {
if (!hdr.getValue().equalsIgnoreCase(values[j])) {
continue;
}
found = true;
break;
}
}
if (!found) {
return false;
}
}
return true;
}
public String getContentLocation() {
return getFirstMimeHeader(HTTPConstants.HEADER_CONTENT_LOCATION);
}
public void setContentLocation(String loc) {
setMimeHeader(HTTPConstants.HEADER_CONTENT_LOCATION, loc);
}
public void setContentId(String newCid) {
setMimeHeader(HTTPConstants.HEADER_CONTENT_ID, newCid);
}
public String getContentId() {
return getFirstMimeHeader(HTTPConstants.HEADER_CONTENT_ID);
}
public java.util.Iterator getMatchingMimeHeaders(final String[] match) {
return mimeHeaders.getMatchingHeaders(match);
}
public java.util.Iterator getNonMatchingMimeHeaders(final String[] match) {
return mimeHeaders.getNonMatchingHeaders(match);
}
public Iterator getAllMimeHeaders() {
return mimeHeaders.getAllHeaders();
}
/**
* Changes the first header entry that matches the given name
* to the given value, adding a new header if no existing
* header matches. This method also removes all matching
* headers but the first.
*
*
Note that RFC822 headers can only contain US-ASCII * characters.
* @param name aString
giving the
* name of the header for which to search
* @param value a String
giving the
* value to be set for the header whose name matches the
* given name
* @throws java.lang.IllegalArgumentException if
* there was a problem with the specified mime header name
* or value
*/
public void setMimeHeader(String name, String value) {
mimeHeaders.setHeader(name, value);
}
/** Removes all the MIME header entries. */
public void removeAllMimeHeaders() {
mimeHeaders.removeAllHeaders();
}
/**
* Removes all MIME headers that match the given name.
* @param header - the string name of the MIME
* header/s to be removed
*/
public void removeMimeHeader(String header) {
mimeHeaders.removeHeader(header);
}
/**
* Gets the DataHandler
object for this
* AttachmentPart
object.
* @return the DataHandler
object associated with
* this AttachmentPart
object
* @throws SOAPException if there is
* no data in this AttachmentPart
object
*/
public DataHandler getDataHandler() throws SOAPException {
if(datahandler == null) {
throw new SOAPException(Messages.getMessage("noContent"));
}
return datahandler;
}
/**
* Sets the given DataHandler
object as the
* data handler for this AttachmentPart
object.
* Typically, on an incoming message, the data handler is
* automatically set. When a message is being created and
* populated with content, the setDataHandler
* method can be used to get data from various data sources into
* the message.
* @param datahandler DataHandler
object to
* be set
* @throws java.lang.IllegalArgumentException if
* there was a problem with the specified
* DataHandler
object
*/
public void setDataHandler(DataHandler datahandler) {
if(datahandler == null) {
throw new java.lang.IllegalArgumentException(
Messages.getMessage("illegalArgumentException00"));
}
this.datahandler = datahandler;
setMimeHeader(HTTPConstants.HEADER_CONTENT_TYPE, datahandler.getContentType());
//now look at the source of the data
javax.activation.DataSource ds = datahandler.getDataSource();
if (ds instanceof ManagedMemoryDataSource) {
//and get the filename if appropriate
extractFilename((ManagedMemoryDataSource)ds);
}
}
/**
* Gets the content of this AttachmentPart
object
* as a Java object. The type of the returned Java object
* depends on (1) the DataContentHandler
object
* that is used to interpret the bytes and (2) the
* Content-Type
given in the header.
*
* For the MIME content types "text/plain", "text/html" and
* "text/xml", the DataContentHandler
object does
* the conversions to and from the Java types corresponding to
* the MIME types. For other MIME types,the
* DataContentHandler
object can return an
* InputStream
object that contains the content data as
* raw bytes.
A JAXM-compliant implementation must, as a minimum,
* return a java.lang.String
object corresponding
* to any content stream with a Content-Type
* value of text/plain
and a
* javax.xml.transform.StreamSource
object
* corresponding to a content stream with a
* Content-Type
value of text/xml
. For
* those content types that an installed
* DataContentHandler
object does not understand, the
* DataContentHandler
object is required to
* return a java.io.InputStream
object with the
* raw bytes.
* AttachmentPart
object
* @throws SOAPException if there is no content set
* into this AttachmentPart
object or if there
* was a data transformation error
*/
public Object getContent() throws SOAPException {
if(contentObject != null) {
return contentObject;
}
if(datahandler == null) {
throw new SOAPException(Messages.getMessage("noContent"));
}
javax.activation.DataSource ds = datahandler.getDataSource();
InputStream is = null;
try {
is = ds.getInputStream();;
} catch (java.io.IOException io) {
log.error(Messages.getMessage("javaIOException00"), io);
throw new SOAPException(io);
}
if (ds.getContentType().equals("text/plain")) {
try {
byte[] bytes = new byte[is.available()];
IOUtils.readFully(is, bytes);
return new String(bytes);
} catch (java.io.IOException io) {
log.error(Messages.getMessage("javaIOException00"), io);
throw new SOAPException(io);
}
} else if (ds.getContentType().equals("text/xml")) {
return new StreamSource(is);
} else if (ds.getContentType().equals("image/gif") ||
ds.getContentType().equals("image/jpeg")) {
try {
return ImageIOFactory.getImageIO().loadImage(is);
} catch (Exception ex) {
log.error(Messages.getMessage("javaIOException00"), ex);
throw new SOAPException(ex);
}
}
return is;
}
/**
* Sets the content of this attachment part to that of the
* given Object
and sets the value of the
* Content-Type
header to the given type. The type of the
* Object
should correspond to the value given for
* the Content-Type
. This depends on the particular
* set of DataContentHandler
objects in use.
* @param object the Java object that makes up
* the content for this attachment part
* @param contentType the MIME string that
* specifies the type of the content
* @throws java.lang.IllegalArgumentException if
* the contentType does not match the type of the content
* object, or if there was no
* DataContentHandler
object for this content
* object
* @see #getContent() getContent()
*/
public void setContent(Object object, String contentType) {
ManagedMemoryDataSource source = null;
setMimeHeader(HTTPConstants.HEADER_CONTENT_TYPE, contentType);
if (object instanceof String) {
try {
String s = (String) object;
java.io.ByteArrayInputStream bais =
new java.io.ByteArrayInputStream(s.getBytes());
source = new ManagedMemoryDataSource(bais,
ManagedMemoryDataSource.MAX_MEMORY_DISK_CACHED,
contentType, true);
extractFilename(source);
datahandler = new DataHandler(source);
contentObject = object;
return;
} catch (java.io.IOException io) {
log.error(Messages.getMessage("javaIOException00"), io);
throw new java.lang.IllegalArgumentException(
Messages.getMessage("illegalArgumentException00"));
}
} else if (object instanceof java.io.InputStream) {
try {
source = new ManagedMemoryDataSource((java.io.InputStream) object,
ManagedMemoryDataSource.MAX_MEMORY_DISK_CACHED,
contentType, true);
extractFilename(source);
datahandler = new DataHandler(source);
contentObject = null; // the stream has been consumed
return;
} catch (java.io.IOException io) {
log.error(Messages.getMessage("javaIOException00"), io);
throw new java.lang.IllegalArgumentException(Messages.getMessage
("illegalArgumentException00"));
}
} else if (object instanceof StreamSource) {
try {
source = new ManagedMemoryDataSource(((StreamSource)object).getInputStream(),
ManagedMemoryDataSource.MAX_MEMORY_DISK_CACHED,
contentType, true);
extractFilename(source);
datahandler = new DataHandler(source);
contentObject = null; // the stream has been consumed
return;
} catch (java.io.IOException io) {
log.error(Messages.getMessage("javaIOException00"), io);
throw new java.lang.IllegalArgumentException(Messages.getMessage
("illegalArgumentException00"));
}
} else {
throw new java.lang.IllegalArgumentException(
Messages.getMessage("illegalArgumentException00"));
}
}
/**
* Clears out the content of this
* AttachmentPart
object. The MIME header portion is left
* untouched.
*/
public void clearContent() {
datahandler = null;
contentObject = null;
}
/**
* Returns the number of bytes in this
* AttachmentPart
object.
* @return the size of this AttachmentPart
object
* in bytes or -1 if the size cannot be determined
* @throws SOAPException if the content of this
* attachment is corrupted of if there was an exception
* while trying to determine the size.
*/
public int getSize() throws SOAPException {
if (datahandler == null) {
return 0;
}
ByteArrayOutputStream bout = new ByteArrayOutputStream();
try {
datahandler.writeTo(bout);
} catch (java.io.IOException ex) {
log.error(Messages.getMessage("javaIOException00"), ex);
throw new SOAPException(Messages.getMessage("javaIOException01", ex.getMessage()), ex);
}
return bout.size();
}
/**
* Gets all the values of the header identified by the given
* String
.
* @param name the name of the header; example:
* "Content-Type"
* @return a String
array giving the value for the
* specified header
* @see #setMimeHeader(java.lang.String, java.lang.String) setMimeHeader(java.lang.String, java.lang.String)
*/
public String[] getMimeHeader(String name) {
return mimeHeaders.getHeader(name);
}
/**
* Content ID.
*
* @return the contentId reference value that should be used directly
* as an href in a SOAP element to reference this attachment.
* Not part of JAX-RPC, JAX-M, SAAJ, etc.
*/
public String getContentIdRef() {
return Attachments.CIDprefix + getContentId();
}
/**
* Maybe add file name to the attachment.
*
* @param source the source of the data
*/
private void extractFilename(ManagedMemoryDataSource source) {
//check for there being a file
if(source.getDiskCacheFile()!=null) {
String path = source.getDiskCacheFile().getAbsolutePath();
setAttachmentFile(path);
}
}
/**
* Set the filename of this attachment part.
*
* @param path the new file path
*/
protected void setAttachmentFile(String path) {
attachmentFile=path;
}
/**
* Detach the attachment file from this class, so it is not cleaned up.
* This has the side-effect of making subsequent calls to
* getAttachmentFile() return null
.
*/
public void detachAttachmentFile() {
attachmentFile=null;
}
/**
* Get the filename of this attachment.
*
* @return the filename or null for an uncached file
*/
public String getAttachmentFile() {
return attachmentFile;
}
/**
* when an attachment part is disposed, any associated files
* are deleted, and the datahandler itself nulled. The object
* is no longer completely usable, at this point
*/
public synchronized void dispose() {
if (attachmentFile != null) {
javax.activation.DataSource ds = datahandler.getDataSource();
if (ds instanceof ManagedMemoryDataSource) {
((ManagedMemoryDataSource) ds).delete(); //and delete the file
} else {
File f = new File(attachmentFile);
//no need to check for existence here.
f.delete();
}
//set the filename to null to stop repeated use
setAttachmentFile(null);
}
//clean up the datahandler, as it will have been
//invalidated if it was bound to a file; if it wasnt
//we get to release memory anyway
datahandler = null;
}
}