FileDocCategorySizeDatePackage
DimeBodyPart.javaAPI DocApache Axis 1.420700Sat Apr 22 18:57:28 BST 2006org.apache.axis.attachments

DimeBodyPart

public class DimeBodyPart extends Object
Holds one attachment DIME part.

Fields Summary
protected static Log
log
protected Object
data
protected DimeTypeNameFormat
dtnf
protected byte[]
type
protected byte[]
id
static final byte
POSITION_FIRST
static final byte
POSITION_LAST
private static final byte
CHUNK
private static final byte
CHUNK_NEXT
private static final byte
ONLY_CHUNK
private static final byte
LAST_CHUNK
private static int
MAX_TYPE_LENGTH
private static int
MAX_ID_LENGTH
static final long
MAX_DWORD
private static final byte[]
pad
static final byte
CURRENT_OPT_T
Constructors Summary
protected DimeBodyPart()


    // fixme: don't use? is this for inheritance only? I can't find any
    //  classes that extend this
      
public DimeBodyPart(byte[] data, DimeTypeNameFormat format, String type, String id)
Create a DIME Attachment Part.

param
data a byte array containing the data as the attachment.
param
format the type format for the data.
param
type the type of the data
param
id the ID for the DIME part.

        System.arraycopy(data, 0, this.data = new byte[ data.length], 0, data.length);
        this.dtnf = format;
        this.type = type.getBytes();
        if (this.type.length > MAX_TYPE_LENGTH)
            throw new IllegalArgumentException(Messages.getMessage
                    ("attach.dimetypeexceedsmax",
                    "" + this.type.length, "" + MAX_TYPE_LENGTH));
        this.id = id.getBytes();
        if (this.id.length > MAX_ID_LENGTH)
            throw new IllegalArgumentException(
                    Messages.getMessage("attach.dimelengthexceedsmax", "" + this.id.length,
                        "" + MAX_ID_LENGTH));
    
public DimeBodyPart(DataHandler dh, DimeTypeNameFormat format, String type, String id)
Create a DIME Attachment Part.

param
dh the data for the attachment as a JAF datahadler.
param
format the type format for the data.
param
type the type of the data
param
id the ID for the DIME part.

        this.data = dh;
        this.dtnf = format;
        if (type == null || type.length() == 0)
            type = "application/octet-stream";
        this.type = type.getBytes();
        if (this.type.length > MAX_TYPE_LENGTH)
            throw new IllegalArgumentException(Messages.getMessage(
                        "attach.dimetypeexceedsmax",
                        "" + this.type.length, "" + MAX_TYPE_LENGTH));
        this.id = id.getBytes();
        if (this.id.length > MAX_ID_LENGTH)
            throw new IllegalArgumentException(Messages.getMessage(
            "attach.dimelengthexceedsmax",
            "" + this.id.length, "" + MAX_ID_LENGTH));
    
public DimeBodyPart(DataHandler dh, String id)
Create a DIME Attachment Part.

param
dh the data for the attachment as a JAF datahadler. The type and foramt is derived from the DataHandler.
param
id the ID for the DIME part.

        this(dh, DimeTypeNameFormat.MIME, dh.getContentType(), id);

        String ct = dh.getContentType();

        if (ct != null) {
            ct = ct.trim();
            if (ct.toLowerCase().startsWith("application/uri")) {
                StringTokenizer st = new StringTokenizer(ct, " \t;");
                String t = st.nextToken(" \t;");

                if (t.equalsIgnoreCase("application/uri")) {
                    for (; st.hasMoreTokens();) {
                        t = st.nextToken(" \t;");
                        if (t.equalsIgnoreCase("uri")) {
                            t = st.nextToken("=");
                            if (t != null) {
                                t = t.trim();
                                if (t.startsWith("\"")) t =
                                  t.substring(1);

                                if (t.endsWith("\"")) t =
                                  t.substring(0, t.length() - 1);
                                this.type = t.getBytes();
                                this.dtnf = DimeTypeNameFormat.URI;
                            }
                            return;
                        } else if (t.equalsIgnoreCase("uri=")) {
                            t = st.nextToken(" \t;");
                            if (null != t && t.length() != 0) {
                                t = t.trim();
                                if (t.startsWith("\"")) t=
                                  t.substring(1);
                                if (t.endsWith("\"")) t=
                                  t.substring(0, t.length() - 1);
                                this.type = t.getBytes();
                                this.dtnf = DimeTypeNameFormat.URI;
                                return;
                            }
                        } else if (t.toLowerCase().startsWith("uri=")) {
                            if (-1 != t.indexOf('=")) {
                                t = t.substring(t.indexOf('=")).trim();
                                if (t.length() != 0) {
                                    t = t.trim();
                                    if (t.startsWith("\"")) t =
                                      t.substring(1);

                                    if (t.endsWith("\""))
                                     t = t.substring(0, t.length() - 1);
                                    this.type = t.getBytes();
                                    this.dtnf = DimeTypeNameFormat.URI;
                                    return;

                                }
                            }
                        }
                    }
                }
            }
        }
    
Methods Summary
static final intdimePadding(long l)

        return (int) ((4L - (l & 0x3L)) & 0x03L);
    
protected longgetDataSize()

        if (data instanceof byte[]) return ((byte[]) (data)).length;
        if (data instanceof DataHandler)
          return getDataSize((DataHandler) data);
        return -1;
    
protected longgetDataSize(javax.activation.DataHandler dh)

        long dataSize = -1L;

        try {
            DataSource ds = dh.getDataSource();

            //Do files our selfs since this is costly to read in. Ask the file system.
            // This is 90% of the use of attachments.
            if (ds instanceof javax.activation.FileDataSource) {
                javax.activation.FileDataSource fdh =
                    (javax.activation.FileDataSource) ds;
                java.io.File df = fdh.getFile();

                if (!df.exists()) {
                    throw new RuntimeException(
                            Messages.getMessage("noFile",
                                df.getAbsolutePath()));
                }
                dataSize = df.length();
            } else {
                dataSize = 0;
                java.io.InputStream in = ds.getInputStream();
                byte[] readbuf = new byte[64 * 1024];
                int bytesread;

                do {
                    bytesread = in.read(readbuf);
                    if (bytesread > 0) dataSize += bytesread;
                }
                while (bytesread > -1);

                if (in.markSupported()) {
                    //Leave the stream open for future reading
                    // and reset the stream pointer to the first byte
                    in.reset();
                } else {
                    //FIXME: bug http://nagoya.apache.org/jira/secure/ViewIssue.jspa?key=AXIS-1126
                    //if we close this then how can we read the file? eh?
                    in.close();
                }
            }
        } catch (Exception e) {
            //TODO: why are exceptions swallowed here?
            log.error(Messages.getMessage("exception00"), e);
        }
        return dataSize;
    
longgetTransmissionSize(long chunkSize)

        long size = 0;
        size += id.length;
        size += dimePadding(id.length);
        size += type.length;
        size += dimePadding(type.length);
        //no options.
        long dataSize = getDataSize();

        if(0 == dataSize){
            size+=12; //header size.
        }else{

            long fullChunks = dataSize / chunkSize;
            long lastChunkSize = dataSize % chunkSize;

            if (0 != lastChunkSize) size += 12; //12 bytes for fixed header
            size += 12 * fullChunks; //add additional header size for each chunk.
            size += fullChunks * dimePadding(chunkSize);
            size += dimePadding(lastChunkSize);
            size += dataSize;
        }
        return size;
    
longgetTransmissionSize()

        return getTransmissionSize(MAX_DWORD);
    
voidsend(java.io.OutputStream os, byte position, DynamicContentDataHandler dh, long maxchunk)
Special case for dynamically generated content. maxchunk is currently ignored since the default is 2GB. The chunk size is retrieved from the DynamicContentDataHandler

param
os
param
position
param
dh
param
maxchunk
throws
java.io.IOException

    	
    		BufferedInputStream in = new BufferedInputStream(dh.getInputStream());
    		
    		final int myChunkSize = dh.getChunkSize();
    		
    		byte[] buffer1 = new byte[myChunkSize]; 
    		byte[] buffer2 = new byte[myChunkSize]; 
    		
    		int bytesRead1 = 0 , bytesRead2 = 0;

    		bytesRead1 = in.read(buffer1);
    		
    		if(bytesRead1 < 0) {
                sendHeader(os, position, 0, ONLY_CHUNK);
                os.write(pad, 0, dimePadding(0));
                return;
    		}
    		byte chunkbyte = CHUNK;
    		do {
    			bytesRead2 = in.read(buffer2);
    			
    			if(bytesRead2 < 0) {
    				//last record...do not set the chunk bit.
    				//buffer1 contains the last chunked record!!
    			   
    			    //Need to distinguish if this is the first 
    			    //chunk to ensure the TYPE and ID are sent
    			    if ( chunkbyte == CHUNK ){
    			        chunkbyte = ONLY_CHUNK;
    			    } else {
    			        chunkbyte = LAST_CHUNK;
    			    }
    				sendChunk(os, position, buffer1, 0, bytesRead1, chunkbyte);
    				break;
    			}
    			
    			sendChunk(os, position, buffer1, 0, bytesRead1, chunkbyte);
    			//set chunk byte to next chunk flag to avoid
    			//sending TYPE and ID on subsequent chunks
    			chunkbyte = CHUNK_NEXT;
    			//now that we have written out buffer1, copy buffer2 into to buffer1
    			System.arraycopy(buffer2,0,buffer1,0,myChunkSize);
    			bytesRead1 = bytesRead2;
    			
    		}while(bytesRead2 > 0);
    
voidsend(java.io.OutputStream os, byte position, byte[] data, long maxchunk)


          
            
        send(os, position, data, 0, data.length, maxchunk);
    
voidsend(java.io.OutputStream os, byte position, byte[] data, int offset, int length, long maxchunk)


        byte chunknext = 0;

        do {
            int sendlength = (int) Math.min(maxchunk, length - offset);

            sendChunk(os, position, data, offset, sendlength, (byte)
                ((sendlength < (length - offset) ? CHUNK : 0)
                 | chunknext));
            offset += sendlength;
            chunknext = CHUNK_NEXT;
        }
        while (offset < length);
    
voidsend(java.io.OutputStream os, byte position, javax.activation.DataHandler dh, long maxchunk)

        java.io.InputStream in = null;
        try {
            long dataSize = getDataSize();
            in = dh.getInputStream();
            byte[] readbuf = new byte[64 * 1024];
            int bytesread;

            sendHeader(os, position, dataSize, (byte) 0);
            long totalsent = 0;

            do {
                bytesread = in.read(readbuf);
                if (bytesread > 0) {
                    os.write(readbuf, 0, bytesread);
                    totalsent += bytesread;
                }
            }
            while (bytesread > -1);
            os.write(pad, 0, dimePadding(totalsent));
        }
        finally {
            if (in != null) {
                try {
                  in.close();
                }
                catch (IOException e) {
                  // ignore
                }
            }
        }
    
protected voidsendChunk(java.io.OutputStream os, byte position, byte[] data, byte chunk)


        sendChunk(os, position, data, 0, data.length, chunk);
    
protected voidsendChunk(java.io.OutputStream os, byte position, byte[] data, int offset, int length, byte chunk)


        sendHeader(os, position, length, chunk);
        os.write(data, offset, length);
        os.write(pad, 0, dimePadding(length));
    
protected voidsendHeader(java.io.OutputStream os, byte position, long length, byte chunk)


       
      
              
        byte[] fixedHeader = new byte[12];
        
        //If first chunk then send TYPE and ID 
        boolean isFirstChunk = ((chunk == CHUNK) || (chunk == ONLY_CHUNK));
        //If chunk is ONLY_NEXT then 
        //reset to CHUNK so CF is set.
        //If chunk is ONLY_CHUNK (first and last chunk)  
        //then do not set CF since this is the only chunk
        if ( chunk == CHUNK_NEXT ){
            chunk = CHUNK;
        } else if ( chunk  == ONLY_CHUNK ){
            chunk = LAST_CHUNK;
        }
                
        //VERSION
        fixedHeader[0] = (byte)((DimeMultiPart.CURRENT_VERSION << 3) & 0xf8);

        // B, E
        fixedHeader[0] |= (byte) ((position & (byte) 0x6)
         & ((chunk & CHUNK) != 0 ? ~POSITION_LAST : ~0) &
                    ((chunk & CHUNK_NEXT) != 0 ? ~POSITION_FIRST : ~0));
        fixedHeader[0] |= (chunk & CHUNK);
        
        boolean MB = 0 != (0x4 & fixedHeader[0]);
        //TYPE_T
        if ( MB || isFirstChunk ){ //If this is a follow on chunk dont send id again.
            fixedHeader[1] = (byte) ((dtnf.toByte() << 4) & 0xf0);
        } else {
        	fixedHeader[1] = (byte) 0x00;
        }
        
        //OPT_T
        fixedHeader[1] |= (byte) (CURRENT_OPT_T & 0xf);

        //OPTION_LENGTH
        fixedHeader[2] = (byte) 0;
        fixedHeader[3] = (byte) 0;

        //ID_LENGTH
        if  ( (MB || isFirstChunk) && (id != null && id.length > 0))   { //If this is a follow on chunk dont send id again.
            fixedHeader[4] = (byte) ((id.length >>> 8) & 0xff);
            fixedHeader[5] = (byte) ((id.length) & 0xff);
        } else {
        	fixedHeader[4] = (byte) 0;
            fixedHeader[5] = (byte) 0;
        }

        //TYPE_LENGTH
        if (  MB || isFirstChunk )  {
            fixedHeader[6] = (byte) ((type.length >>> 8) & 0xff);
            fixedHeader[7] = (byte) ((type.length) & 0xff);
        } else {
        	fixedHeader[6] = (byte) 0;
            fixedHeader[7] = (byte) 0;
        }

        //DATA_LENGTH
        fixedHeader[8] = (byte) ((length >>> 24) & 0xff);
        fixedHeader[9] = (byte) ((length >>> 16) & 0xff);
        fixedHeader[10] = (byte) ((length >>> 8) & 0xff);
        fixedHeader[11] = (byte) (length & 0xff);

        os.write(fixedHeader);

        //OPTIONS + PADDING
        // (NONE)

        //ID + PADDING
        if ( (MB || isFirstChunk) && (id != null && id.length > 0))  {
            os.write(id);
            os.write(pad, 0, dimePadding(id.length));
        }

        //TYPE + PADDING
        if ( MB || isFirstChunk )  {
            os.write(type);
            os.write(pad, 0, dimePadding(type.length));
        }
    
voidwrite(java.io.OutputStream os, byte position, long maxchunk)
Write to stream the data using maxchunk for the largest junk.

param
os the OutputStream to write to
param
position the position to write
param
maxchunk the maximum length of any one chunk
throws
IOException if there was a problem writing data to the stream

        if (maxchunk < 1) throw new IllegalArgumentException(
                    Messages.getMessage("attach.dimeMaxChunkSize0", "" + maxchunk));
        if (maxchunk > MAX_DWORD) throw new IllegalArgumentException(
                    Messages.getMessage("attach.dimeMaxChunkSize1", "" + maxchunk));
        if (data instanceof byte[]) {
            send(os, position, (byte[]) data, maxchunk);
        } else if (data instanceof DynamicContentDataHandler) {
            send(os, position, (DynamicContentDataHandler) data, maxchunk);
        } else if (data instanceof DataHandler) {
            DataSource source = ((DataHandler)data).getDataSource();
            DynamicContentDataHandler dh2 = new DynamicContentDataHandler(source);
            send(os, position, dh2, maxchunk);
        }
    
voidwrite(java.io.OutputStream os, byte position)
Write to stream the data using the default largest chunk size.

param
os the OutputStream to write to
param
position the position to write
throws
IOException if there was a problem writing data to the stream

        write(os, position, MAX_DWORD);