org.apache.axis.attachments.AttachmentsImpl Maven / Gradle / Ivy
/*
* 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.
*/
/* @author Rob Jellinghaus ([email protected]) */
/* @author Rick Rineholt */
package org.apache.axis.attachments;
import org.apache.axis.AxisFault;
import org.apache.axis.Part;
import org.apache.axis.SOAPPart;
import org.apache.axis.components.logger.LogFactory;
import org.apache.axis.utils.Messages;
import org.apache.commons.logging.Log;
import javax.activation.DataHandler;
import javax.activation.DataSource;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
/**
* Implements the Attachment interface, via an actual Hashmap of actual
* AttachmentParts.
*/
public class AttachmentsImpl implements Attachments {
protected static Log log =
LogFactory.getLog(AttachmentsImpl.class.getName());
/** Field attachments. */
private HashMap attachments = new java.util.HashMap();
/** Field orderedAttachments. */
private LinkedList orderedAttachments = new LinkedList();
/** Field soapPart. */
protected SOAPPart soapPart = null;
/**
* The actual stream to manage the multi-related input stream.
*/
protected MultiPartInputStream mpartStream =
null;
/**
* The form of the attachments, whether MIME or DIME.
*/
protected int sendtype= Attachments.SEND_TYPE_NOTSET;
/**
* This is the content location as specified in SOAP with Attachments.
* This maybe null if the message had no Content-Location specifed.
*/
protected String contentLocation = null;
/**
* The HashMap for DataHandler Managements.
*/
private HashMap stackDataHandler = new HashMap();
/**
* Used to distribute attachment streams without caching them.
*/
private IncomingAttachmentStreams _streams = null;
private boolean _askedForAttachments = false;
private boolean _askedForStreams = false;
/**
* Construct one of these on a parent Message.
* Should only ever be called by Message constructor!
*
* @param intialContents should be anything but today only a stream is
* supported.
* @param contentType The mime content type of the stream for transports
* that provide it.
* @param contentLocation
*
* @throws org.apache.axis.AxisFault
*/
public AttachmentsImpl(
Object intialContents, String contentType, String contentLocation)
throws org.apache.axis.AxisFault {
if (contentLocation != null) {
contentLocation = contentLocation.trim();
if (contentLocation.length() == 0) {
contentLocation = null;
}
}
this.contentLocation = contentLocation;
if (contentType != null) {
if (contentType.equals(org.apache.axis.Message.MIME_UNKNOWN)) {
} else {
java.util.StringTokenizer st =
new java.util.StringTokenizer(contentType, " \t;");
if (st.hasMoreTokens()) {
String token = st.nextToken();
if (token.equalsIgnoreCase(
org.apache.axis.Message.MIME_MULTIPART_RELATED)) {
sendtype= SEND_TYPE_MIME;
mpartStream =
new org.apache.axis.attachments.MultiPartRelatedInputStream(
contentType,
(java.io.InputStream) intialContents);
if (null == contentLocation) {
// If the content location is not specified as
// of the main message use the SOAP content location.
contentLocation = mpartStream.getContentLocation();
if (contentLocation != null) {
contentLocation = contentLocation.trim();
if (contentLocation.length() == 0) {
contentLocation = null;
}
}
}
soapPart = new org.apache.axis.SOAPPart(null,
mpartStream,
false);
MultiPartRelatedInputStream specificType = (MultiPartRelatedInputStream) mpartStream;
_streams = new MultipartAttachmentStreams(specificType.boundaryDelimitedStream, specificType.orderedParts);
} else if (token.equalsIgnoreCase(org.apache.axis.Message.MIME_APPLICATION_DIME)) {
try{
mpartStream=
new MultiPartDimeInputStream( (java.io.InputStream) intialContents);
soapPart = new org.apache.axis.SOAPPart(null, mpartStream, false);
}catch(Exception e){ throw org.apache.axis.AxisFault.makeFault(e);}
sendtype= SEND_TYPE_DIME;
MultiPartDimeInputStream specificType = (MultiPartDimeInputStream) mpartStream;
_streams = new DimeAttachmentStreams(specificType.dimeDelimitedStream);
} else if (token.indexOf(org.apache.axis.Message.CONTENT_TYPE_MTOM)!=-1){
sendtype = SEND_TYPE_MTOM;
}
}
}
}
}
/**
* Copies attachment references from the multipartStream to local list.
* Done only once per object creation.
*
* @throws AxisFault
*/
private void mergeinAttachments() throws AxisFault {
if (mpartStream != null) {
Collection atts = mpartStream.getAttachments();
if(contentLocation == null)
contentLocation= mpartStream.getContentLocation();
mpartStream = null;
setAttachmentParts(atts);
}
}
/**
* This method uses getAttacmentByReference() to look for attachment.
* If attachment has been found, it will be removed from the list, and
* returned to the user.
* @param reference The reference that referers to an attachment.
*
* @return The part associated with the removed attachment, or null.
*
* @throws org.apache.axis.AxisFault
*/
public Part removeAttachmentPart(String reference)
throws org.apache.axis.AxisFault {
if (_askedForStreams) {
throw new IllegalStateException(Messages.getMessage("concurrentModificationOfStream"));
}
multipart = null;
dimemultipart = null;
mergeinAttachments();
Part removedPart = getAttachmentByReference(reference);
if (removedPart != null) {
attachments.remove(removedPart.getContentId());
attachments.remove(removedPart.getContentLocation());
orderedAttachments.remove(removedPart);
}
return removedPart;
}
/**
* Adds an existing attachment to this list.
* Note: Passed part will be bound to this message.
* @param newPart new part to add
* @return Part old attachment with the same Content-ID, or null.
*
* @throws org.apache.axis.AxisFault
*/
public Part addAttachmentPart(Part newPart)
throws org.apache.axis.AxisFault {
if (_askedForStreams) {
throw new IllegalStateException(Messages.getMessage("concurrentModificationOfStream"));
}
multipart = null;
dimemultipart = null;
mergeinAttachments();
Part oldPart = (Part) attachments.put(newPart.getContentId(), newPart);
if (oldPart != null) {
orderedAttachments.remove(oldPart);
attachments.remove(oldPart.getContentLocation());
}
orderedAttachments.add(newPart);
if (newPart.getContentLocation() != null) {
attachments.put(newPart.getContentLocation(), newPart);
}
return oldPart;
}
public Part createAttachmentPart(Object datahandler)
throws org.apache.axis.AxisFault {
// Searching for the same attachements
Integer key = new Integer(datahandler.hashCode());
if (stackDataHandler.containsKey(key)) {
return (Part)stackDataHandler.get(key);
}
multipart = null;
dimemultipart = null;
mergeinAttachments();
if (!(datahandler instanceof javax.activation.DataHandler)) {
throw new org.apache.axis.AxisFault(
Messages.getMessage(
"unsupportedAttach", datahandler.getClass().getName(),
javax.activation.DataHandler.class.getName()));
}
Part ret =
new AttachmentPart((javax.activation.DataHandler) datahandler);
addAttachmentPart(ret);
// Store the current DataHandler with its key
stackDataHandler.put(key, ret);
return ret;
}
/**
* Add the collection of parts.
*
* @param parts
*
* @throws org.apache.axis.AxisFault
*/
public void setAttachmentParts(java.util.Collection parts)
throws org.apache.axis.AxisFault {
if (_askedForStreams) {
throw new IllegalStateException(Messages.getMessage("concurrentModificationOfStream"));
}
removeAllAttachments();
if ((parts != null) && !parts.isEmpty()) {
for (java.util.Iterator i = parts.iterator(); i.hasNext();) {
Object part = i.next();
if (null != part) {
if(part instanceof Part)
addAttachmentPart((Part)part);
else
createAttachmentPart(part);
}
}
}
}
/**
* This method should look at a refernce and determine if it is a CID: or
* url to look for attachment.
*
* Note: if Content-Id or Content-Location headers have changed by outside
* code, lookup will not return proper values. In order to change these
* values attachment should be removed, then added again.
* @param reference The reference in the xml that referers to an attachment.
*
* @return The part associated with the attachment.
*
* @throws org.apache.axis.AxisFault
*/
public Part getAttachmentByReference(String reference)
throws org.apache.axis.AxisFault {
if (_askedForStreams) {
throw new IllegalStateException(Messages.getMessage("concurrentModificationOfStream"));
}
if (null == reference) {
return null;
}
reference = reference.trim();
if (0 == reference.length()) {
return null;
}
mergeinAttachments();
//This search will pickit up if its fully qualified location or if it's a content-id
// that is not prefixed by the cid.
Part ret = (Part) attachments.get(reference);
if( null != ret) return ret;
if (!reference.startsWith(Attachments.CIDprefix) && (null != contentLocation)) {
//Not a content-id check to see if its a relative location id.
String fqreference = contentLocation;
if (!fqreference.endsWith("/")) {
fqreference += "/";
}
if (reference.startsWith("/")) {
fqreference += reference.substring(1);
} else {
fqreference += reference;
}
// lets see if we can get it as Content-Location
ret = (AttachmentPart) attachments.get(fqreference);
}
if( null == ret && reference.startsWith(Attachments.CIDprefix)){
//This is a content-id lets see if we have it.
ret = (Part) attachments.get( reference.substring(4));
}
return ret;
}
/**
* This method will return all attachments as a collection.
*
* @return A collection of attachments.
*
* @throws org.apache.axis.AxisFault
*/
public java.util.Collection getAttachments()
throws org.apache.axis.AxisFault {
if (_askedForStreams) {
throw new IllegalStateException(Messages.getMessage("concurrentModificationOfStream"));
}
mergeinAttachments();
return new LinkedList(orderedAttachments);
}
/**
* From the complex stream return the root part.
* Today this is SOAP.
*
* @return the root Part
*/
public Part getRootPart() {
return soapPart;
}
public void setRootPart(Part newRoot) {
try {
this.soapPart = (SOAPPart) newRoot;
multipart = null;
dimemultipart = null;
} catch (ClassCastException e) {
throw new ClassCastException(Messages.getMessage("onlySOAPParts"));
}
}
/** multipart , cached entries for the stream of attachment that are going to be sent. */
javax.mail.internet.MimeMultipart multipart = null;
DimeMultiPart dimemultipart = null;
/**
* Get the content length of the stream.
*
* @return the content length of the stream
*
* @throws org.apache.axis.AxisFault
*/
public long getContentLength() throws org.apache.axis.AxisFault {
if (_askedForStreams) {
throw new IllegalStateException(Messages.getMessage("concurrentModificationOfStream"));
}
mergeinAttachments();
int sendtype= this.sendtype == SEND_TYPE_NOTSET ? SEND_TYPE_DEFAULT : this.sendtype;
try {
if(sendtype == SEND_TYPE_MIME || sendtype == SEND_TYPE_MTOM)
return org.apache.axis.attachments.MimeUtils.getContentLength(
multipart != null ? multipart : (multipart = org.apache.axis.attachments.MimeUtils.createMP(soapPart.getAsString(), orderedAttachments, getSendType())));
else if (sendtype == SEND_TYPE_DIME)return createDimeMessage().getTransmissionSize();
} catch (Exception e) {
throw AxisFault.makeFault(e);
}
return 0;
}
/**
* Creates the DIME message
*
* @return a DIME part
*
* @throws org.apache.axis.AxisFault if the part could not be built
*/
protected DimeMultiPart createDimeMessage() throws org.apache.axis.AxisFault{
int sendtype= this.sendtype == SEND_TYPE_NOTSET ? SEND_TYPE_DEFAULT : this.sendtype;
if (sendtype == SEND_TYPE_DIME){
if(dimemultipart== null){
dimemultipart= new DimeMultiPart();
dimemultipart.addBodyPart(new DimeBodyPart(
soapPart.getAsBytes(), DimeTypeNameFormat.URI,
"http://schemas.xmlsoap.org/soap/envelope/",
"uuid:714C6C40-4531-442E-A498-3AC614200295"));
for( java.util.Iterator i= orderedAttachments.iterator();
i.hasNext(); ){
AttachmentPart part= (AttachmentPart)i.next();
DataHandler dh= AttachmentUtils.
getActivationDataHandler(part);
dimemultipart.addBodyPart(new
DimeBodyPart(dh,part.getContentId()));
}
}
}
return dimemultipart;
}
/**
* Write the content to the stream.
*
* @param os
*
* @throws org.apache.axis.AxisFault
*/
public void writeContentToStream(java.io.OutputStream os)
throws org.apache.axis.AxisFault {
int sendtype= this.sendtype == SEND_TYPE_NOTSET ?
SEND_TYPE_DEFAULT : this.sendtype;
try{
mergeinAttachments();
if(sendtype == SEND_TYPE_MIME || sendtype == SEND_TYPE_MTOM){
org.apache.axis.attachments.MimeUtils.writeToMultiPartStream(os,
(multipart != null)
? multipart
: (multipart =
org.apache.axis.attachments.MimeUtils.createMP(
soapPart.getAsString(), orderedAttachments, getSendType())));
for (java.util.Iterator i = orderedAttachments.iterator();
i.hasNext();) {
AttachmentPart part = (AttachmentPart) i.next();
DataHandler dh =
AttachmentUtils.getActivationDataHandler(part);
DataSource ds = dh.getDataSource();
if ((ds != null) && (ds instanceof ManagedMemoryDataSource)) {
((ManagedMemoryDataSource) ds).delete();
}
}
}else if (sendtype == SEND_TYPE_DIME)createDimeMessage().write(os);
}catch(Exception e){ throw org.apache.axis.AxisFault.makeFault(e);}
}
/**
* Gets the content type for the whole stream.
*
* @return the content type for the whole stream
*
* @throws org.apache.axis.AxisFault
*/
public String getContentType() throws org.apache.axis.AxisFault {
mergeinAttachments();
int sendtype= this.sendtype == SEND_TYPE_NOTSET ? SEND_TYPE_DEFAULT :
this.sendtype;
if(sendtype == SEND_TYPE_MIME || sendtype == SEND_TYPE_MTOM)
return org.apache.axis.attachments.MimeUtils.getContentType((multipart
!= null)
? multipart
: (multipart =
org.apache.axis.attachments.MimeUtils.createMP(
soapPart.getAsString(),
orderedAttachments, getSendType())));
else return org.apache.axis.Message.MIME_APPLICATION_DIME;
}
/**
* This is the number of attachments.
*
* @return the number of attachments
*/
public int getAttachmentCount() {
if (_askedForStreams) {
throw new IllegalStateException(Messages.getMessage("concurrentModificationOfStream"));
}
try {
mergeinAttachments();
// force a serialization of the message so that
// any attachments will be added
soapPart.saveChanges();
return orderedAttachments.size();
} catch (AxisFault e) {
log.warn(Messages.getMessage("exception00"),e);
}
return 0;
}
/**
* Determine if an object is to be treated as an attchment.
*
* @param value the value that is to be determined if
* its an attachment.
*
* @return True if value should be treated as an attchment.
*/
public boolean isAttachment(Object value) {
return AttachmentUtils.isAttachment(value);
}
/**
* Removes all AttachmentPart
objects that have
* been added to this SOAPMessage
object.
*
* This method does not touch the SOAP part.
*/
public void removeAllAttachments() {
if (_askedForStreams) {
throw new IllegalStateException(Messages.getMessage("concurrentModificationOfStream"));
}
try {
multipart = null;
dimemultipart = null;
mergeinAttachments();
attachments.clear();
orderedAttachments.clear();
stackDataHandler.clear();
} catch (AxisFault af){
log.warn(Messages.getMessage("exception00"),af);
}
}
/**
* Retrieves all the AttachmentPart
objects
* that have header entries that match the specified headers.
* Note that a returned attachment could have headers in
* addition to those specified.
* @param headers a MimeHeaders
* object containing the MIME headers for which to
* search
* @return an iterator over all attachments that have a header
* that matches one of the given headers
*/
public java.util.Iterator getAttachments(
javax.xml.soap.MimeHeaders headers) {
if (_askedForStreams) {
throw new IllegalStateException(Messages.getMessage("concurrentModificationOfStream"));
}
java.util.Vector vecParts = new java.util.Vector();
java.util.Iterator iterator = GetAttachmentsIterator();
while(iterator.hasNext()){
Part part = (Part) iterator.next();
if(part instanceof AttachmentPart){
if(((AttachmentPart)part).matches(headers)){
vecParts.add(part);
}
}
}
return vecParts.iterator();
}
/**
* get an iterator over all attachments. This
* @return iterator of Part Objects; some of which may be
* AttachmentPart instances
* @see org.apache.axis.Part
* @see AttachmentPart
*/
private java.util.Iterator GetAttachmentsIterator() {
java.util.Iterator iterator = attachments.values().iterator();
return iterator;
}
/**
* Create a new attachment Part in this Message.
* Will actually, and always, return an AttachmentPart.
*
* @return a new attachment Part
*
* @throws org.apache.axis.AxisFault
*/
public Part createAttachmentPart() throws org.apache.axis.AxisFault {
return new AttachmentPart();
}
public void setSendType( int sendtype){
if( sendtype < 1)
throw new IllegalArgumentException("");
if( sendtype > SEND_TYPE_MAX )
throw new IllegalArgumentException("");
this.sendtype= sendtype;
}
public int getSendType(){
return sendtype;
}
/**
* dispose of the attachments and their files; do not use the object
* after making this call.
*/
public void dispose() {
java.util.Iterator iterator = GetAttachmentsIterator();
while (iterator.hasNext()) {
Part part = (Part) iterator.next();
if (part instanceof AttachmentPart) {
AttachmentPart apart=(AttachmentPart)part;
apart.dispose();
}
}
}
// consider type-safe e-num here?
/**
* Determine how an object typically sent as attachments are to
* be represented. Currently, MIME DIME and NONE are reccognised.
*
* @param value a String representing a sending type, treated in a
* case-insensetive manner
* @return an int
send type code
*/
public static int getSendType(String value) {
if (value.equalsIgnoreCase("MTOM")) return SEND_TYPE_MTOM;
if (value.equalsIgnoreCase("MIME")) return SEND_TYPE_MIME;
if (value.equalsIgnoreCase("DIME")) return SEND_TYPE_DIME;
if (value.equalsIgnoreCase("NONE")) return SEND_TYPE_NONE;
return SEND_TYPE_NOTSET;
}
/**
* For a given sendType value, return a string representation.
*
* @param value a type code integer
* @return a String
representation of value
*/
public static String getSendTypeString(int value) {
if (value == SEND_TYPE_MTOM) {
return "MTOM";
}
if (value == SEND_TYPE_MIME) {
return "MIME";
}
if (value == SEND_TYPE_DIME) {
return "DIME";
}
if (value == SEND_TYPE_NONE) {
return "NONE";
}
return null;
}
/**
* Once this method is called, attachments can only be accessed via the InputStreams.
* Any other access to the attachments collection (e.g. via getAttachments()) is
* prohibited and will cause a IllegalStateException to be thrown.
*
* @return All of the attachment streams.
*/
public IncomingAttachmentStreams getIncomingAttachmentStreams() {
if (_askedForAttachments) {
throw new IllegalStateException(Messages.getMessage("concurrentModificationOfStream"));
}
_askedForStreams = true;
mpartStream = null; // todo: comment
return _streams;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy