FileDocCategorySizeDatePackage
MultipartObject.javaAPI DocphoneME MR2 API (J2ME)48329Wed May 02 18:00:44 BST 2007com.sun.tck.wma.mms

MultipartObject

public class MultipartObject extends com.sun.tck.wma.sms.MessageObject implements com.sun.tck.wma.MultipartMessage
Implements an MMS message for the MMS message connection.

Fields Summary
Vector
to
The array of "to" addresses.
Vector
cc
The array of "cc" addresses.
Vector
bcc
The array of "bcc" addresses.
Vector
parts
The array of message parts.
String
startContentID
The Content-ID of the part that starts the message.
String
subject
The Subject field of the message.
String[]
headerValues
The array of message headers.
String
applicationID
The Application Identifier of the agent to process the message.
String
replyToApplicationID
The Application Identifier of the return agent to process the message.
static final String[]
ALLOWED_HEADER_FIELDS
Array of allowed MMS header fields.
static final String[]
DEFAULT_HEADER_VALUES
Array of default header values.
static final String[]
KNOWN_HEADER_FIELDS
Array of known header fields.
static final int
MAX_TOTAL_SIZE
Maximum size of MMS message. Default value is 30730 (30K)
static final String
STREAM_SIGNATURE
The content type for the MMS message.
Constructors Summary
public MultipartObject(String toAddress)
Construct a multipart message and initialize the target address.

param
toAddress the address of the recipient. May be null.

        super(MessageConnection.MULTIPART_MESSAGE, null);
        to = new Vector();
        cc = new Vector();
        bcc = new Vector();
        parts = new Vector();
        startContentID = null;
        subject = null;
        applicationID = null;
        replyToApplicationID = null;
        setupHeaderFields();
        if (toAddress != null) {
            addAddress("to", toAddress);
        }
    
Methods Summary
public booleanaddAddress(java.lang.String type, java.lang.String address)
Adds an address to the multipart message.

param
type the address type ("to", "cc" or "bcc") as a String. Each message can have none or multiple "to", "cc" and "bcc" addresses. Each address is added separately. The type is not case-sensitive.
param
address the address as a String
return
true if it was possible to add the address, else false
exception
java.lang.IllegalArgumentException if type is none of "to", "cc", or "bcc" or if address is not valid.
see
#setAddress(String)


        MMSAddress parsedAddress = checkValidAddress(address);
        String appID = parsedAddress.appId;
        if (appID != null) {
            checkApplicationID(appID);
        }
        
        Vector which = getAddressList(type);
        if (!which.contains(address)) {
            which.addElement(address);
            return true;
        }
        return false;
    
public voidaddMessagePart(com.sun.tck.wma.MessagePart part)
Attaches a MessagePart to the multipart message.

param
part MessagePart to add
exception
java.lang.IllegalArgumentException if the Content-ID of the MessagePart conflicts with a Content-ID of a MessagePart already contained in this MultiPartMessage. The Content-IDs must be unique within a MultipartMessage.
exception
NullPointerException if the parameter is null
exception
SizeExceededException if it's not possible to attach the MessagePart.

    
                                                                                             
          
        String thisContentID = part.getContentID();
        boolean duplicateContentID = false;
        int totalSizeSoFar = 0;
        int numPartsSoFar = parts.size();
        for (int i = 0; i < numPartsSoFar; ++i) {
            MessagePart onePart = (MessagePart)parts.elementAt(i);
            if (thisContentID.equals(onePart.getContentID())) {
                throw new IllegalArgumentException(
                    "Cannot add duplicate content-id: " + thisContentID);
            }
            totalSizeSoFar += onePart.getLength();
        }
        if (totalSizeSoFar + part.getLength() > MAX_TOTAL_SIZE) {
            throw new SizeExceededException(
                "Adding this MessagePart would exceed max size of " + 
                MAX_TOTAL_SIZE + " bytes");
        }
        parts.addElement(part);
    
voidcheckApplicationID(java.lang.String newAppID)
Checks an application ID to see if it can be legally added to this message. The spec requires that only a single applicationID can be specified for any MultipartMessage.

param
newAppID the candidate applicationID to check. May be null
throws
IllegalArgumentException if newAppID conflicts with an applicationID already specified for this message.

        if (applicationID != null) {
            if (!applicationID.equals(newAppID)) {
                throw new IllegalArgumentException(
                   "Only one Application-ID can be specified per message");
            }
        } else {
            applicationID = newAppID;
        }   
    
static voidcheckHeaderValue(int headerIndex, java.lang.String value)
Checks the header field value.

param
headerIndex the index of the header field to check
param
value the value to be checked
exception
Error if an invalid header index is requested
exception
IllegalArgumentException if the value is not a valid delivery time or priority

        switch (headerIndex) {
            case 0: // X-Mms-Delivery-Time
                try {
                    Long.parseLong(value);
                    return;
                } catch (NumberFormatException nfe) {
                    // do nothing... we'll report the error in a second
                }
                break;
            case 1: // X-Mms-Priority
            {
                String lower = value.toLowerCase();
                if (lower.equals("normal") || lower.equals("high") ||
                    lower.equals("low")) {
                    return;
                }
                // we'll report the error in a second
                break;
            }
            default:
                throw new Error("Unknown headerIndex: " + headerIndex);
        }
        // report the error
        throw new IllegalArgumentException("Illegal value for header " +
            ALLOWED_HEADER_FIELDS[headerIndex] + ": " + value);                
    
MMSAddresscheckValidAddress(java.lang.String addr)
Checks if the string is a valid MMS address according to the grammar in Appendix D of the spec.

param
addr the address to check
return
MMSAddress representing the valid address, otherwise null.

        MMSAddress parsedAddress = MMSAddress.getParsedMMSAddress(addr);
        // check to make sure there's a device address
        if (parsedAddress == null || 
            parsedAddress.type == MMSAddress.INVALID_ADDRESS ||
            parsedAddress.type == MMSAddress.APP_ID) {
            throw new IllegalArgumentException("Invalid destination address: "
                + addr);
        }
        return parsedAddress;
    
private voidcleanupAppID()
Cleans application Id value.

        Vector addresses = to;
        boolean checkedTo = false;
        boolean checkedCC = false;
        int currIndex = 0;
        boolean matchedAppID = false; 
        while (true) {
            if (currIndex >= addresses.size()) {
                if (!checkedTo) {
                    checkedTo = true;
                    addresses = cc;
                    currIndex = 0;
                    continue;
                } else if (!checkedCC) {
                    checkedCC = true;
                    addresses = bcc;
                    currIndex = 0;
                    continue;
                } else {
                    break;
                }
                    
            }
            String addr = (String)addresses.elementAt(currIndex++); 
            MMSAddress parsedAddress = MMSAddress.getParsedMMSAddress(addr);
            if (parsedAddress == null || 
                parsedAddress.type == MMSAddress.INVALID_ADDRESS ||
                parsedAddress.type == MMSAddress.APP_ID) {
                throw new IllegalStateException(
                    "Invalid MMS address: " + addr);
            }
            String thisAppID = parsedAddress.appId;
            if (thisAppID != null && thisAppID.equals(applicationID)) {
                matchedAppID = true;
            }
        }
        if (!matchedAppID) {
            applicationID = null;
        }
    
public static com.sun.tck.wma.mms.MultipartObjectcreateFromByteArray(byte[] data)
Create a message object from a serialized byte array.

param
data a serialized byte array of a message object
return
the multipart message object
exception
IOException if any I/O errors occur


        ByteArrayInputStream bais = new ByteArrayInputStream(data);
        DataInputStream dis = new DataInputStream(bais);
        
        String signature = dis.readUTF();
        if (!signature.equals(STREAM_SIGNATURE)) {
            throw new IOException("invalid data format");
        }
        // eat the first 6 entries: "X-Mms-Message-Type", "m-send-req", 
        // "X-Mms-Transaction-ID", <transactionID>, "X-Mms-Version", "1.0"
        for (int i = 0; i < 6; ++i) {
            dis.readUTF();
        }
        
        String[] headerValues = new String[ALLOWED_HEADER_FIELDS.length];
        String nextField = dis.readUTF();
        int headerIndex;
        while ((headerIndex = getHeaderFieldIndex(nextField)) != -1) { 
            headerValues[headerIndex] = dis.readUTF();
            nextField = dis.readUTF();   
        }
        String fromAddress = null;
        if (nextField.equals("From")) {
            fromAddress = "mms://" + dis.readUTF();
            nextField = dis.readUTF();
        }
        Vector to = new Vector();
        if (nextField.equals("To")) {
            readVector(dis, to, true);
            nextField = dis.readUTF();
        }
        Vector cc = new Vector();
        if (nextField.equals("Cc")) {
            readVector(dis, cc, true);
            nextField = dis.readUTF();
        }
        Vector bcc = new Vector();
        if (nextField.equals("Bcc")) {
            readVector(dis, bcc, true);
            nextField = dis.readUTF();            
        }
        long date = 0L;
        if (nextField.equals("Date")) {
            String dateStr = dis.readUTF();
            try {
                date = Long.parseLong(dateStr);
            } catch (NumberFormatException nfe) {
                date = 0L;
            }
            nextField = dis.readUTF();
        }
        String subject = null;
        if (nextField.equals("Subject")) {
            subject = dis.readUTF();
            nextField = dis.readUTF();
        }
        // nextField is "Content-Type"
        String startContentID = null;
        String applicationID = null;
        String replyToApplicationID = null;
        Vector contentTypeElements = new Vector();
        readVector(dis, contentTypeElements, false);
        int numContentTypeElements = contentTypeElements.size();
        for (int i = 0; i < numContentTypeElements; ++i) {
            String element = (String)contentTypeElements.elementAt(i);
            if (element.startsWith("start = <")) {
                startContentID = element.substring(9);
                startContentID = startContentID.substring(0, 
                    startContentID.length()-1);
            } else if (element.startsWith("Application-ID = ")) {
                applicationID = element.substring(17);
            } else if (element.startsWith("Reply-To-Application-ID = ")) {
                replyToApplicationID = element.substring(26);
            }
        }        
        nextField = dis.readUTF();
        // nextField is "nEntries"
        int numParts = 0;
        String numPartsStr = dis.readUTF();
        try {
            numParts = Integer.parseInt(numPartsStr);
        } catch (NumberFormatException nfe) {
            numParts = 0;
        }
        Vector parts = new Vector();
        for (int i = 0; i < numParts; ++i) {
            parts.addElement(createMessagePart(dis));
        }
        dis.close();
        bais.close();

        MultipartObject mpo = new MultipartObject(fromAddress);
        mpo.setTimeStamp(date);
        mpo.headerValues = headerValues;
        mpo.subject = subject;
        mpo.startContentID = startContentID;
        mpo.to = to;
        mpo.cc = cc;
        /* 
         * Uncomment this if you want the "bcc"s to be visible to the recipients
        mpo.bcc = bcc;
         */
        mpo.parts = parts;
        mpo.applicationID = applicationID;
        mpo.replyToApplicationID = replyToApplicationID;
        return mpo;
    
static com.sun.tck.wma.MessagePartcreateMessagePart(java.io.DataInputStream dis)
Create a new message part from the input stream

param
dis the data input stream for reading
exception
IOException if any I/O errors occur
return
the message object instance

        String nextField = dis.readUTF(); // eats "Content-Type" header
        String contentType = dis.readUTF();
        nextField = dis.readUTF();
        String contentID = null;
        if (nextField.equals("Content-ID")) {
            contentID = dis.readUTF();
            nextField = dis.readUTF();
        }
        String encoding = null;
        if (nextField.equals("Encoding")) {
            encoding = dis.readUTF();
            nextField = dis.readUTF();
        }
        // "Content-Length" was just eaten
        int length = dis.readInt();
        byte[] contents = new byte[length];
        nextField = dis.readUTF(); // eats the "Content" header
        dis.readFully(contents);
        // now separate the content location and mime type
        String mimeType = contentType;
        String contentLocation = null;
        int sepPos = contentType.indexOf(';");
        if (sepPos != -1 && contentType.substring(sepPos).
            startsWith("; name=\"")) {
            contentLocation = contentType.substring(sepPos+8, // ; name="
						    contentType.length()-1);
            mimeType = contentType.substring(0, sepPos);
        }
        return new MessagePart(contents, mimeType, contentID, contentLocation,
			       encoding);
    
public voidfixupReceivedMessageAddresses(java.lang.String senderAddress, java.lang.String myAddress)
Prepares a received message to be sent right back to the sender. Removes this device's address from the "to" and "cc" address lists and sets the sender's address as the first "to" address.

param
senderAddress the sender's address. Should not include the "mms://" prefix, and may contain the ":appID" suffix. May be null.
param
myAddress this device's address. Must not be null.

        String regularAddress = myAddress;
        String plusAddress = myAddress;
        if (regularAddress.charAt(0) == '+") {
            regularAddress = regularAddress.substring(1);
        } else if (plusAddress.charAt(0) != '+") {
            plusAddress = "+" + plusAddress;
        }                              
        // remove ourselves from "to" and "cc" list
        Vector addresses = to;
        for (int i = 0; i < 2; ++i) {                
            int numAdds = addresses.size();
            for (int index = 0; index < numAdds; ++index) {
                String thisAddress = (String)addresses.elementAt(index);
                MMSAddress parsedAddress = 
                    MMSAddress.getParsedMMSAddress(thisAddress);
                if (parsedAddress != null && 
                    (regularAddress.equals(parsedAddress.address) ||
                     plusAddress.equals(parsedAddress.address))) {
                        --numAdds;
                        addresses.removeElementAt(index);
                        --index;
                }
            }
            addresses = cc;
        }
        // set the first "to" address to be the sender's address
        if (senderAddress != null) {
            String formalAddress = senderAddress;
            to.insertElementAt(formalAddress, 0);
            MMSAddress parsedAddress = 
                MMSAddress.getParsedMMSAddress(formalAddress);
            applicationID = parsedAddress.appId;
        } else {
            applicationID = null;
        }
    
public java.lang.StringgetAddress()
Returns the "from" address associated with this message, e.g. address of the sender. If the message is a newly created message, e.g. not a received one, then the first "to" address is returned. Returns null if the "from" or "to" address for the message, dependent on the case, are not set. Note: This design allows sending responses to a received message easily by reusing the same Message object and just replacing the payload. The address field can normally be kept untouched (unless the used messaging protocol requires some special handling of the address).

return
the "from" or "to" address of this message, or null if the address that is expected as a result of this method is not set
see
#setAddress(String)

        String returnMe = null;
        Date tStamp = getTimestamp();
        if (tStamp == null || tStamp.getTime() == 0L) {            
            // not a received message - use the first "to" address
            if (to.size() > 0) {
                returnMe = (String)to.elementAt(0);
            }
        } else {            
            // received - use the "from" address
            returnMe = super.getAddress();
        }       
        return returnMe;
    
java.util.VectorgetAddressList(java.lang.String type)
Gets the requested address list.

param
type the address list to be returned, either "to", "cc" or "bcc"
exception
IllegalArgumentException if some other address list type is requested
return
a list of addresses

        String lower = type.toLowerCase();
        if (lower.equals("to")) {
            return to;
        } else if (lower.equals("cc")) {
            return cc;
        } else if (lower.equals("bcc")) {
            return bcc;
        }
        throw new IllegalArgumentException(
            "Address type is not 'to', 'cc', or 'bcc'");
    
public java.lang.String[]getAddresses(java.lang.String type)
Gets the addresses of the multipart message of the specified type (e.g. "to", "cc", "bcc" or "from") as String. The method is not case sensitive.

param
type the type of addresses to return
return
the addresses as a String array or null if this value is not present.

        if (type.toLowerCase().equals("from")) {
            String address = super.getAddress();
            if (address == null) {
                return null;
            }
            return new String[] { address };
        }
        Vector which = getAddressList(type);
        int num = which.size();
        if (num == 0) {
            return null;
        }
        String[] addresses = new String[num];
        which.copyInto(addresses);
        return addresses;
    
public java.lang.StringgetApplicationID()
Returns the destination application identifier.

return
the destination application identifier, or null if none is set

        return applicationID;
    
public byte[]getAsByteArray()
Gets the message object as a byte array.

exception
IOException if any I/O errors occur
return
the serialized byte array of the message object


                                 
         

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(baos);

        dos.writeUTF(STREAM_SIGNATURE);
        
        dos.writeUTF("X-Mms-Message-Type");
        dos.writeUTF("m-send-req");
        dos.writeUTF("X-Mms-Transaction-ID");
        dos.writeUTF(String.valueOf(System.currentTimeMillis()));      
        dos.writeUTF("X-Mms-Version");
        dos.writeUTF("1.0");
        for (int i = 0; i < ALLOWED_HEADER_FIELDS.length; ++i) {
            String headerValue = headerValues[i];
            if (headerValue != null) {
                dos.writeUTF(ALLOWED_HEADER_FIELDS[i]);
                dos.writeUTF(headerValue);
            }
        }
        String fromAddress = super.getAddress();
        if (fromAddress != null) {
            dos.writeUTF("From");
            dos.writeUTF(getDevicePortionOfAddress(fromAddress));
        }
        if (to.size() != 0) {
            dos.writeUTF("To");
            writeVector(dos, to, true);
        }
        if (cc.size() != 0) {
            dos.writeUTF("Cc");
            writeVector(dos, cc, true);
        }
        if (bcc.size() != 0) {
            dos.writeUTF("Bcc");
            writeVector(dos, bcc, true);
        }
        long date = 0L;
        Date tStamp = getTimestamp();
        if (tStamp != null && (date = tStamp.getTime()) != 0L) {
            dos.writeUTF("Date");
            dos.writeUTF(String.valueOf(date));
        }
        if (subject != null) {
            dos.writeUTF("Subject");
            dos.writeUTF(subject);
        }
        dos.writeUTF("Content-Type");
        Vector contentTypeElements = new Vector();
        if (startContentID != null) {
            contentTypeElements.addElement(
                "application/vnd.wap.multipart.related");
        } else {
            contentTypeElements.addElement(
                "application/vnd.wap.multipart.mixed");
        }
        if (startContentID != null) {
            contentTypeElements.addElement("start = <" + startContentID + ">");
            contentTypeElements.addElement("type = " + 
                getMessagePart(startContentID).getMIMEType());
        }
        if (applicationID != null) {
            contentTypeElements.addElement("Application-ID = " + applicationID);
        }
        if (replyToApplicationID != null) {
            contentTypeElements.addElement("Reply-To-Application-ID = " +
                replyToApplicationID);
        }
        writeVector(dos, contentTypeElements, false);
        dos.writeUTF("nEntries");
        int numParts = parts.size();
        dos.writeUTF(String.valueOf(numParts));
        for (int i = 0; i < numParts; ++i) {
            MessagePart p = (MessagePart)parts.elementAt(i);
            writeMessagePart(dos, p);
        }
        dos.close();
        byte[] returnMe = baos.toByteArray();
        baos.close();
        return returnMe;
    
public byte[]getBodyAsByteArray()
Gets the message object body as a byte array. The body is composed of a single header that states the number of entries, followed by a serialized array of MessagePart objects.

throws
IOException if any I/O errors occur.
return
the serialized byte array of the message body.


        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(baos);

        dos.writeUTF("nEntries");
        int numParts = parts.size();
        dos.writeUTF(String.valueOf(numParts));
        for (int i = 0; i < numParts; ++i) {
            MessagePart p = (MessagePart)parts.elementAt(i);
            writeMessagePart(dos, p);
        }

        dos.close();
        byte[] returnMe = baos.toByteArray();
        baos.close();
        return returnMe;
    
static java.lang.StringgetDevicePortionOfAddress(java.lang.String address)
Returns only the device part of the MMS Address.

return
the device portion of the MMS Address
param
address the MMS address
throws
IllegalArgumentException if the MMS Address has no device portion.

        MMSAddress parsedAddress = MMSAddress.getParsedMMSAddress(address);
        if (parsedAddress == null || parsedAddress.address == null) {
            throw new IllegalArgumentException("MMS Address " 
					       +"has no device portion");
        }
        return parsedAddress.address;
    
public java.lang.StringgetHeader(java.lang.String headerField)
Gets the content of the specific header field of the multipart message.

param
headerField the name of the header field as a String
return
the content of the specified header field as a String or null of the specified header field is not present.
exception
SecurityException if the access to specified header field is restricted
exception
IllegalArgumentException if headerField is unknown
see
Appendix D for known headerFields
see
#setHeader

        if (headerField == null) {
            throw new IllegalArgumentException(
                "headerField must not be null");
        }
        if (isAllowedToAccessHeaderField(headerField)) {                
            int index = getHeaderFieldIndex(headerField);
            if (index != -1) {
                return headerValues[index];
            }
            throw new Error("Allowed to access field but it has no index");
        }
        if (isKnownHeaderField(headerField)) {
            throw new SecurityException(
                "Cannot access restricted header field: " + headerField);
        } else {
            throw new IllegalArgumentException("Unknown header field: " + 
                headerField);
        }
    
public byte[]getHeaderAsByteArray()
Gets the message object header as a byte array. The header is composed of a number of fields and is exclusive of the MessagePart contents.

throws
IOException if any I/O errors occur.
return
the serialized byte array of the message object


        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        DataOutputStream dos = new DataOutputStream(baos);

        dos.writeUTF(STREAM_SIGNATURE);
        
        // Write headers that 
        dos.writeUTF("X-Mms-Message-Type");
        dos.writeUTF("m-send-req");
        dos.writeUTF("X-Mms-Transaction-ID");
        dos.writeUTF(String.valueOf(System.currentTimeMillis()));      
        dos.writeUTF("X-Mms-Version");
        dos.writeUTF("1.0");

        for (int i = 0; i < ALLOWED_HEADER_FIELDS.length; ++i) {
            String headerValue = headerValues[i];
            if (headerValue != null) {
                dos.writeUTF(ALLOWED_HEADER_FIELDS[i]);
                dos.writeUTF(headerValue);
            }
        }
        String fromAddress = super.getAddress();
        if (fromAddress != null) {
            dos.writeUTF("From");
            dos.writeUTF(getDevicePortionOfAddress(fromAddress));
        }
        if (to.size() != 0) {
            dos.writeUTF("To");
            writeVector(dos, to, true);
        }
        if (cc.size() != 0) {
            dos.writeUTF("Cc");
            writeVector(dos, cc, true);
        }
        if (bcc.size() != 0) {
            dos.writeUTF("Bcc");
            writeVector(dos, bcc, true);
        }
        long date = 0L;
        Date tStamp = getTimestamp();
        if (tStamp != null && (date = tStamp.getTime()) != 0L) {
            dos.writeUTF("Date");
            dos.writeUTF(String.valueOf(date));
        }
        if (subject != null) {
            dos.writeUTF("Subject");
            dos.writeUTF(subject);
        }
        dos.writeUTF("Content-Type");
        Vector contentTypeElements = new Vector();
        if (startContentID != null) {
            contentTypeElements.addElement(
                "application/vnd.wap.multipart.related");
        } else {
            contentTypeElements.addElement(
                "application/vnd.wap.multipart.mixed");
        }
        if (startContentID != null) {
            contentTypeElements.addElement("start = <" + startContentID + ">");
            contentTypeElements.addElement("type = " + 
                getMessagePart(startContentID).getMIMEType());
        }
        if (applicationID != null) {
            contentTypeElements.addElement("Application-ID = " + applicationID);
        }
        if (replyToApplicationID != null) {
            contentTypeElements.addElement("Reply-To-Application-ID = " +
                replyToApplicationID);
        }
        writeVector(dos, contentTypeElements, false);
        dos.close();
        byte[] returnMe = baos.toByteArray();
        baos.close();
        return returnMe;
    
static intgetHeaderFieldIndex(java.lang.String headerField)
Gets the location of the requested header from the list of allowed header fields.

param
headerField the header field key to be checked
return
the index of the requested header field, or -1 if the header is not supported

        String lowerFieldName = headerField.toLowerCase();
        for (int i = 0; i < ALLOWED_HEADER_FIELDS.length; ++i) {
            if (lowerFieldName.equals(ALLOWED_HEADER_FIELDS[i].toLowerCase())) {
                return i;
            }
        }
        return -1;
    
public com.sun.tck.wma.MessagePartgetMessagePart(java.lang.String contentID)
This method returns a MessagePart from the message that matches the content-id passed as a parameter.

param
contentID the content-id for the MessagePart to be returned
return
MessagePart that matches the provided content-id or null if there is no MessagePart in this message with the provided content-id
exception
NullPointerException if the parameter is null

        if (contentID == null) {
            throw new NullPointerException("contentID must not be null");
        }
        int numParts = parts.size();
        for (int i = 0; i < numParts; ++i) {
            MessagePart onePart = (MessagePart)parts.elementAt(i);
            if (contentID.equals(onePart.getContentID())) {
                return onePart;
            }
        }
        return null;
    
public com.sun.tck.wma.MessagePart[]getMessageParts()
Returns an array of all MessageParts of this message.

return
array of MessageParts, or null if no MessageParts are available

        int num = parts.size();
        if (num == 0) {
            return null;
        }
        MessagePart[] msgParts = new MessagePart[num];
        parts.copyInto(msgParts);
        return msgParts;
    
java.lang.StringgetReplyToApplicationID()
Gets the "reply-to" application identifier.

return
the return address application identifier, or null if none is set
see
#setReplyToApplicationID

        return replyToApplicationID;
    
public java.lang.StringgetStartContentId()
Returns the contentId of the start MessagePart. The start MessagePart is set in setStartContentId(String)

return
the content-id of the start MessagePart or null if the start MessagePart is not set.
see
#setStartContentId(String)

        return startContentID;
    
public java.lang.StringgetSubject()
Gets the subject of the multipart message.

return
the message subject as a String or null if this value is not present.
see
#setSubject

        return subject;
    
booleanisAllowedToAccessHeaderField(java.lang.String field)
Checks if allowed to access the requested header field.

param
field the header field key to check
return
true if the header exists

        return (getHeaderFieldIndex(field) != -1);
    
static booleanisKnownHeaderField(java.lang.String headerField)
Checks if header field is known.

param
headerField the header field key to check
return
true if the header is known

    
                              
        
        String lowerFieldName = headerField.toLowerCase();
        for (int i = 0; i < KNOWN_HEADER_FIELDS.length; ++i) {
            if (lowerFieldName.equals(KNOWN_HEADER_FIELDS[i].toLowerCase())) {
                return true;
            }
        }
        return false;
    
static voidreadVector(java.io.DataInputStream dis, java.util.Vector v, boolean isAddress)
Reads a vector from an input stream. If the content is an MMS Address, as indicated by the isAddress parameter, then the prefix "mms://" is added to each address.

param
dis the data input stream for reading
param
v the array to be returned
param
isAddress the contents are MMS Addresses
exception
IOException if any I/O errors occur

        String inputStr = dis.readUTF();
        int prevDelim = -2;
        String prefix = "";
        if (isAddress) {
            prefix = "mms://";
        }
        while (prevDelim != -1) {
            int nextDelim = inputStr.indexOf("; ", prevDelim + 2);
            String addStr = null;
            if (nextDelim == -1) {
                addStr = prefix + inputStr.substring(prevDelim + 2);
            } else {
                addStr = prefix + inputStr.substring(prevDelim + 2, nextDelim);
            }
            v.addElement(addStr);
            prevDelim = nextDelim;
        }
    
public booleanremoveAddress(java.lang.String type, java.lang.String address)
Removes an address from the multipart message.

param
type the address type ("to", "cc", or "bcc") as a String
param
address the address as a String
return
true if it was possible to delete the address, else false
throws
NullPointerException is type is null
throws
java.lang.IllegalArgumentException if type is none of "to", "cc", or "bcc"

        Vector which = getAddressList(type);
        boolean result = which.removeElement(address);
        cleanupAppID();
        return result;
    
public voidremoveAddresses()
Removes all addresses of types "to", "cc", "bcc" from the multipart message.

see
#setAddress(String)
see
#addAddress(String, String)

        to.removeAllElements();
        cc.removeAllElements();
        bcc.removeAllElements();
        applicationID = null;
    
public voidremoveAddresses(java.lang.String type)
Removes all addresses of the specified type from the multipart message.

param
type the address type ("to", "cc", or "bcc") as a String
throws
NullPointerException if type is null
throws
java.lang.IllegalArgumentException if type is none of "to", "cc", or "bcc"

        Vector which = getAddressList(type);
        which.removeAllElements();
        cleanupAppID();
    
public booleanremoveMessagePart(com.sun.tck.wma.MessagePart part)
Removes a MessagePart from the multipart message.

param
part MessagePart to delete
return
true if it was possible to remove the MessagePart, else false
exception
NullPointerException id the parameter is null

        if (part == null) {
            throw new NullPointerException("part must not be null");
        }
        if (part.getContentID().equals(startContentID)) {
            startContentID = null;
        }
        return parts.removeElement(part);
    
public booleanremoveMessagePartId(java.lang.String contentID)
Removes a MessagePart with the specific contentID from the multipart message.

param
contentID identifies which MessagePart must be deleted.
return
true if it was possible to remove the MessagePart, else false
exception
NullPointerException if the parameter is null

        if (contentID == null) {
            throw new NullPointerException("contentID must not be null");
        }
        int numParts = parts.size();
        for (int i = 0; i < numParts; ++i) {
            MessagePart onePart = (MessagePart)parts.elementAt(i);
            if (contentID.equals(onePart.getContentID())) {
                if (contentID.equals(startContentID)) {
                    startContentID = null;
                }
                parts.removeElementAt(i);
                return true;
            }
        }
        return false;
    
public booleanremoveMessagePartLocation(java.lang.String contentLocation)
Removes MessageParts with the specific content location from the multipart message. All MessageParts with the specified contentLocation are removed.

param
contentLocation content location (file name) of the MessagePart
return
true if it was possible to remove the MessagePart, else false
exception
NullPointerException if the parameter is null

        if (contentLocation == null) {
            throw new NullPointerException("contentLocation must not be null");
        }
        int numParts = parts.size();
        boolean found = false;
        for (int i = 0; i < numParts; ++i) {
            MessagePart onePart = (MessagePart)parts.elementAt(i);
            if (contentLocation.equals(onePart.getContentLocation())) {
                if (onePart.getContentID().equals(startContentID)) {
                    startContentID = null;
                }
                parts.removeElementAt(i);
                --numParts;
                --i;
                found = true;
            }
        }
        return found;
    
public voidsetAddress(java.lang.String address)
Sets the "to" address associated with this message. It works the same way as addAddress("to", addr). The address may be set to null.

param
address address for the message
see
#getAddress()
see
#addAddress(String, String)

        if (address != null) {
            addAddress("to", address);
        }
        // otherwise it's a no-op.
    
public voidsetFromAddress(java.lang.String fromAddress)
Sets the "from" address.

param
fromAddress the return address, which may be null

        super.setAddress(fromAddress);
    
public voidsetHeader(java.lang.String headerField, java.lang.String headerValue)
Sets the specified header of the multipart message. The header value can be null.

param
headerField the name of the header field as a String
param
headerValue the value of the header as a String
exception
java.lang.IllegalArgumentException if headerField is unknown, or if headerValue is not correct (depends on headerField!)
exception
NullPointerException if headerField is null
exception
SecurityException if the access to specified header field is restricted
see
#getHeader(String)
see
Appendix D

        if (isAllowedToAccessHeaderField(headerField)) {
            int index = getHeaderFieldIndex(headerField);
            if (index != -1) {
                if (headerValue != null) {
                    checkHeaderValue(index, headerValue);
                }
                headerValues[index] = headerValue;
                return;
            }
            throw new Error("Allowed to access field but it has no index");
        }
        if (isKnownHeaderField(headerField)) {
            throw new SecurityException(
                "Cannot access restricted header field: " + headerField);
        } else {
            throw new IllegalArgumentException("Unknown header field: " + 
                headerField);
        }
    
public voidsetReplyToApplicationID(java.lang.String appID)
Sets the "reply-to" application identifier.

param
appID the return address application identifier. May be null.
see
#getReplyToApplicationID

        replyToApplicationID = appID;
    
public voidsetStartContentId(java.lang.String contentId)
Sets the Content-ID of the start MessagePart of a multipart related message. The Content-ID may be set to null. The StartContentId is set for the MessagePart that is used to reference the other MessageParts of the MultipartMessage for presentation or processing purposes.

param
contentId as a String
exception
java.lang.IllegalArgumentException if contentId is none of the added MessagePart objects matches the contentId
see
#getStartContentId()

        if (contentId != null) {
            if (getMessagePart(contentId) == null) {
                throw new IllegalArgumentException("Unknown contentId: "
                    + contentId);
            }
        }
        startContentID = contentId;
    
public voidsetSubject(java.lang.String subject)
Sets the Subject of the multipart message. This value can be null.

param
subject the message subject as a String
see
#getSubject()

        if (subject != null && subject.length() > 40) { // MMS Conformance limit
            throw new IllegalArgumentException("Subject exceeds 40 chars");
        }
        this.subject = subject;
    
voidsetupHeaderFields()
Sets default values for all allowed header fields.

        headerValues = new String[ALLOWED_HEADER_FIELDS.length];
        for (int i = 0; i < DEFAULT_HEADER_VALUES.length; ++i) {
            headerValues[i] = DEFAULT_HEADER_VALUES[i];
        }
    
static voidwriteMessagePart(java.io.DataOutputStream dos, com.sun.tck.wma.MessagePart p)
Writes a message part to the output stream

param
dos the data output stream for writing
param
p the message part to be written
exception
IOException if any I/O errors occur

        dos.writeUTF("Content-Type");
        StringBuffer contentType = new StringBuffer(p.getMIMEType());
        String loc = p.getContentLocation(); 
        if (loc != null) {
            contentType.append("; name=\"");
            contentType.append(loc);
            contentType.append("\"");
        }
        dos.writeUTF(contentType.toString());
        String id = p.getContentID();
        if (id != null) {
            dos.writeUTF("Content-ID");
            dos.writeUTF(id);
        }
        String enc = p.getEncoding();
        if (enc != null) {
            dos.writeUTF("Encoding");
            dos.writeUTF(enc);
        }
        // the payload
        dos.writeUTF("Content-Length");
        dos.writeInt(p.getLength());
        dos.writeUTF("Content");
        dos.write(p.getContent());
    
static voidwriteVector(java.io.DataOutputStream dos, java.util.Vector v, boolean isAddress)
Writes a vector to an output stream. If the contents are MMS addresses, as indicated by the isAddress parameter, then only the device part of the address is placed into the vector, not the application-id, if any.

param
dos the data output stream for writing
param
v the array to be written
param
isAddress is the contents of the vector an MMS address.
exception
IOException if any I/O errors occur

        StringBuffer buff = new StringBuffer(); 
        int len = v.size();
        String appendMe = null; 
        if (len > 0) {
            appendMe = (String)v.elementAt(0);
            if (isAddress) {
                appendMe = getDevicePortionOfAddress(appendMe);
            }
            buff.append(appendMe);
        }
        for (int i = 1; i < len; ++i) {
            buff.append("; ");
            appendMe = (String)v.elementAt(i);
            if (isAddress) {
                appendMe = getDevicePortionOfAddress(appendMe);
            }
            buff.append(appendMe);
        }
        dos.writeUTF(buff.toString());