javaextensions/wma/mms/javasrc/com/nokia/mj/impl/mms/MMSConnectionImpl.java
changeset 21 2a9601315dfc
child 78 71ad690e91f5
equal deleted inserted replaced
18:e8e63152f320 21:2a9601315dfc
       
     1 /*
       
     2 * Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:
       
    15 *
       
    16 */
       
    17 
       
    18 
       
    19 package com.nokia.mj.impl.mms;
       
    20 
       
    21 import java.io.IOException;
       
    22 import java.io.InterruptedIOException;
       
    23 import javax.wireless.messaging.*;
       
    24 
       
    25 import com.nokia.mj.impl.utils.Logger;
       
    26 import com.nokia.mj.impl.mms.MmsPropertyRetriever;
       
    27 import com.nokia.mj.impl.rt.support.ShutdownListener;
       
    28 import com.nokia.mj.impl.rt.support.ApplicationUtils;
       
    29 
       
    30 public final class MMSConnectionImpl implements MessageConnection
       
    31 {
       
    32     private static final int INITIAL = 0;
       
    33 
       
    34     private static final int OPEN = 1;
       
    35 
       
    36     private static final int CLOSED = 2;
       
    37 
       
    38     // current state of execution
       
    39     private int iState;
       
    40 
       
    41     // status of send
       
    42     private int iSendError = 0;
       
    43 
       
    44     // number of received messages
       
    45     private int iMessagesOnQueue;
       
    46 
       
    47     // number of notifications to be done
       
    48     private int iNotificationsToMake;
       
    49 
       
    50     // handle to the native side
       
    51     private int iNativeHandle;
       
    52 
       
    53     // waiting for message
       
    54     private boolean iMessageWaiting;
       
    55 
       
    56     // any message notification missed
       
    57     private boolean iMissedMessage;
       
    58 
       
    59     // Is Server Connection
       
    60     private boolean iServerConnection;
       
    61 
       
    62     // synchronization for reading message
       
    63     private final Object iReadLock;
       
    64 
       
    65     // synchronization for sending
       
    66     private final Object iSendLock;
       
    67 
       
    68     // synchronization for sending message
       
    69     private final Object iWriteLock;
       
    70 
       
    71     // synchronization for closing
       
    72     private final Object iCloseLock;
       
    73 
       
    74     // synchronization for receiving
       
    75     private final Object iMessageLock;
       
    76 
       
    77     private String iUri;
       
    78 
       
    79     // Application Id
       
    80     private String iAppID = null;
       
    81 
       
    82     // the listener used for messages receiving notifications
       
    83     private MessageListener iMessageListener;
       
    84 
       
    85     public MMSConnectionImpl(String aUri, boolean aServerConnection)
       
    86     throws IOException
       
    87     {
       
    88         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
    89                    "+ MMSConnectionImpl::MMSConnectionImpl()");
       
    90         iUri = aUri;
       
    91         iState = INITIAL;
       
    92         iServerConnection = aServerConnection;
       
    93         // create the native side peer
       
    94         iNativeHandle = _createPeer(iServerConnection, iUri);
       
    95         iReadLock = new Object();
       
    96         iWriteLock = new Object();
       
    97         iCloseLock = new Object();
       
    98         iMessageLock = new Object();
       
    99         iSendLock = new Object();
       
   100         // register for shutdown listening
       
   101         setShutdownListener();
       
   102         if (iServerConnection)
       
   103         {
       
   104             iAppID = aUri.substring("mms://:".length());
       
   105         }
       
   106         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   107                    "- MMSConnectionImpl::MMSConnectionImpl()");
       
   108     }
       
   109 
       
   110     /*
       
   111     * This function registers this object for shutDown.
       
   112     */
       
   113     private void setShutdownListener()
       
   114     {
       
   115         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   116                    "+ MMSConnectionImpl::setShutdownListener()");
       
   117         // Get the insatnce of ApplicationUtils.
       
   118         ApplicationUtils appUtils = ApplicationUtils.getInstance();
       
   119 
       
   120         // Get the name of the application.
       
   121         appUtils.addShutdownListener(new ShutdownListener()
       
   122         {
       
   123             //The method that gets called when Application is shutting down
       
   124             public void shuttingDown()
       
   125             {
       
   126                 try
       
   127                 {
       
   128                     close();
       
   129                 }
       
   130                 catch (IOException e)
       
   131                 {
       
   132                     //Nothing to do, just ignore
       
   133                     Logger.LOG(Logger.EWMA, Logger.EInfo, e.toString());
       
   134                 }
       
   135             }
       
   136         });
       
   137         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   138                    "- MMSConnectionImpl::setShutdownListener()");
       
   139     }
       
   140 
       
   141     /**
       
   142      * open() is only called when a MIDlet calls Connector.open() a MIDlet will
       
   143      * not be able to access the Connection until open() has completed and a
       
   144      * reference has been returned. It should then only be called once, by only
       
   145      * one thread. particularly, a Connection cannot be closed by a MIDlet until
       
   146      * it has been fully opened.
       
   147      */
       
   148     public void open()
       
   149     {
       
   150         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   151                    "+ MMSConnectionImpl::open()");
       
   152         if (iState == INITIAL)
       
   153         {
       
   154             iState = OPEN;
       
   155             // in case of server connection a notifier thread is created which
       
   156             // waits in the native side and informs the application when there
       
   157             // is an incoming message.
       
   158             if (iServerConnection)
       
   159             {
       
   160                 new Thread(new Runnable()
       
   161                 {
       
   162                     public void run()
       
   163                     {
       
   164                         _openConnection(iNativeHandle);
       
   165                     }
       
   166                 }).start();
       
   167             }
       
   168         }
       
   169         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   170                    "- MMSConnectionImpl::open()");
       
   171     }
       
   172 
       
   173     /**
       
   174      * close() is only called when a MIDlet calls close() on a connection that
       
   175      * is opened by calling Connector.open(). A MIDlet will not be able to access
       
   176      * the Connection after calling close() on that connection.
       
   177      */
       
   178     public void close() throws IOException
       
   179     {
       
   180         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   181                    "+ MMSConnectionImpl::close()");
       
   182         synchronized (iCloseLock)
       
   183         {
       
   184             if (iState != CLOSED)
       
   185             {
       
   186                 iState = CLOSED;
       
   187                 _closeConnection(iNativeHandle);
       
   188                 // notify the notifier thread if it is waiting for a receive()
       
   189                 // or setMessageListener() to be called
       
   190                 synchronized (iMessageLock)
       
   191                 {
       
   192                     iMessageLock.notify();
       
   193                 }
       
   194                 // notify the receive operation about connection closed
       
   195                 synchronized (iReadLock)
       
   196                 {
       
   197                     iReadLock.notify();
       
   198                 }
       
   199                 _dispose(iNativeHandle);
       
   200             }
       
   201         }
       
   202         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   203                    "- MMSConnectionImpl::close()");
       
   204     }
       
   205 
       
   206     /**
       
   207      * Returns the number of segments required for sending this Message.
       
   208      */
       
   209     public int numberOfSegments(Message aMessage)
       
   210     {
       
   211         // For MMS numberOfSegments is always 1.
       
   212         return 1;
       
   213     }
       
   214 
       
   215     private int getMMSMaxSize()
       
   216     {
       
   217         return MmsPropertyRetriever.getMMSMaxSize();
       
   218     }
       
   219 
       
   220     /**
       
   221      * Method for creating a Multipart Message object. If it is a client
       
   222      * connection The destination address of the newly created messages will be
       
   223      * set to the destination part of the URI provided when this connection was
       
   224      * created.
       
   225      *
       
   226      * @param aType
       
   227      *            The type of the message to be created. It can only be
       
   228      *            "Multipart"
       
   229      */
       
   230     public Message newMessage(String aType)
       
   231     {
       
   232         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   233                    "+ MMSConnectionImpl::newMessage()");
       
   234         if (MessageConnection.MULTIPART_MESSAGE.equals(aType))
       
   235         {
       
   236             if (iServerConnection)
       
   237             {
       
   238                 Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   239                            "- MMSConnectionImpl::newMessage()");
       
   240                 return new MultipartMessageImpl(null, 0, getMMSMaxSize());
       
   241             }
       
   242             else
       
   243             {
       
   244                 Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   245                            "- MMSConnectionImpl::newMessage()");
       
   246                 return new MultipartMessageImpl(iUri, 0, getMMSMaxSize());
       
   247             }
       
   248         }
       
   249         // unrecognized type
       
   250         throw new IllegalArgumentException(
       
   251             "Unrecognized message type: " + aType);
       
   252     }
       
   253 
       
   254     /**
       
   255      * Method for creating a Multipart Message object
       
   256      *
       
   257      * @param aType
       
   258      *            The type of the message to be created. It can only be
       
   259      *            "Multipart"
       
   260      * @param aAddress
       
   261      *            the destination address of the Message
       
   262      */
       
   263     public Message newMessage(String aType, String aAddress)
       
   264     {
       
   265         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   266                    "+ MMSConnectionImpl::newMessage()");
       
   267         if (MessageConnection.MULTIPART_MESSAGE.equals(aType))
       
   268         {
       
   269             Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   270                        "- MMSConnectionImpl::newMessage()");
       
   271             return new MultipartMessageImpl(aAddress, 0, getMMSMaxSize());
       
   272         }
       
   273         // unrecognized type
       
   274         throw new IllegalArgumentException(
       
   275             "Unrecognized message type " + aType);
       
   276 
       
   277     }
       
   278 
       
   279     /**
       
   280      * Method for sending a certain message. Only Multipart Messages can be sent
       
   281      * through this connection. The Message to sent is validated before sending.
       
   282      *
       
   283      * @param aMsg
       
   284      *            The message to be sent
       
   285      * @exceptions  throws IOException if there is any n/w problem or if
       
   286      *             connection is already closed
       
   287      * @exceptions  throws InterruptedIOException if a timeout occurs or if the
       
   288      *             connection is closed while sending.
       
   289      * @exceptions  throws IllegalArguementException if any of the header field
       
   290      *             is not specified
       
   291      */
       
   292     public void send(Message aMsg) throws IOException, InterruptedIOException
       
   293     {
       
   294         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   295                    "+ MMSConnectionImpl::send()");
       
   296         // validate the message to be sent
       
   297         MultipartMessageImpl mMsg = validateMessage(aMsg);
       
   298         if (iServerConnection)
       
   299         {
       
   300             mMsg.setReplyToAppID(iAppID);
       
   301         }
       
   302         else
       
   303         {
       
   304             // validate the client-side message
       
   305             validateClientMessage(mMsg);
       
   306         }
       
   307         // Before sending the message serialize it
       
   308         byte[] bMsg = mMsg.serialize();
       
   309         // to synchronize send functionality
       
   310         synchronized (iWriteLock)
       
   311         {
       
   312             synchronized (iSendLock)
       
   313             {
       
   314                 // send operation should not be carried out while close is in
       
   315                 // progress
       
   316                 synchronized (iCloseLock)
       
   317                 {
       
   318                     if (iState == CLOSED)
       
   319                     {
       
   320                         throw new IOException("Sending message failed: " +
       
   321                                               ExceptionStrings.CONNECTION_CLOSED);
       
   322                     }
       
   323                     //checking for valid permissions
       
   324                     ApplicationUtils appUtils = ApplicationUtils.getInstance();
       
   325                     MMSPermissionImpl permission = new MMSPermissionImpl(
       
   326                         "mms://*", "send",
       
   327                         getRecipientsCount(mMsg));
       
   328                     appUtils.checkPermission(permission);
       
   329                     // send the message
       
   330                     int status = _send(bMsg, 0, bMsg.length, mMsg.getAddress(),
       
   331                                        iNativeHandle);
       
   332                     if (status < 0)
       
   333                     {
       
   334                         _checkError(status);
       
   335                     }
       
   336                     // wait till the message was sent successfully
       
   337                     try
       
   338                     {
       
   339                         iSendLock.wait();
       
   340                     }
       
   341                     catch (InterruptedException e)
       
   342                     {
       
   343                         Logger.ELOG(Logger.EWMA, "Message sending failed", e);
       
   344                     }
       
   345                     if (iSendError < 0)
       
   346                     {
       
   347                         _checkError(iSendError);
       
   348                     }
       
   349                 }
       
   350             }
       
   351         }
       
   352         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   353                    "- MMSConnectionImpl::send()");
       
   354     }
       
   355 
       
   356     /**
       
   357      * Callback through which the Native notifies about the sending of a Message
       
   358      * or any error while sending a message
       
   359      *
       
   360      * @param1 result  the status of send operation
       
   361      */
       
   362     protected void messageSentCallback(int aResult)
       
   363     {
       
   364         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   365                    "+ MMSConnectionImpl::messageSentCallback()");
       
   366         synchronized (iSendLock)
       
   367         {
       
   368             iSendError = aResult;
       
   369             iSendLock.notify();
       
   370         }
       
   371         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   372                    "- MMSConnectionImpl::messageSentCallback()");
       
   373     }
       
   374 
       
   375     /**
       
   376      * Receive is a 3 step process: 1) Wait for some incoming message 2)
       
   377      * Retrieve the the message 3) Construct a Multipart Message
       
   378      *
       
   379      * @exceptions throws IOException if the connection is already closed.
       
   380      * @exceptions throws InterruptedIOException if the connection is closed
       
   381      *             while receiving
       
   382      * @returns the constructed message
       
   383      */
       
   384     synchronized public Message receive() throws IOException,
       
   385                 InterruptedIOException
       
   386     {
       
   387         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   388                    "+ MMSConnectionImpl::receive()");
       
   389         if (!iServerConnection)
       
   390         {
       
   391             // Not Supported in Client MODE
       
   392             throw new IOException(ExceptionStrings.CLIENT_MODE);
       
   393         }
       
   394         Message rMsg;
       
   395         synchronized (iReadLock)
       
   396         {
       
   397             // check for connection
       
   398             if (iState == CLOSED)
       
   399             {
       
   400                 throw new IOException("Receiving message failed: " +
       
   401                                       ExceptionStrings.CONNECTION_CLOSED);
       
   402             }
       
   403             // if no messages were there to receive wait till some message
       
   404             // arrives
       
   405             if (iMessagesOnQueue == 0)
       
   406             {
       
   407                 iMessageWaiting =true;
       
   408                 // notify the notifier thread
       
   409                 synchronized (iMessageLock)
       
   410                 {
       
   411                     iMessageLock.notify();
       
   412                 }
       
   413                 // wait for incoming message notification
       
   414                 try
       
   415                 {
       
   416                     iReadLock.wait();
       
   417                 }
       
   418                 catch (InterruptedException e)
       
   419                 {
       
   420                     Logger.ELOG(Logger.EWMA, "Message receiving failed", e);
       
   421                     throw new InterruptedIOException("");
       
   422                 }
       
   423             }
       
   424             synchronized (iCloseLock)
       
   425             {
       
   426                 //if the connection was closed throw InterruptedIOException
       
   427                 if (iState == CLOSED)
       
   428                 {
       
   429                     throw new InterruptedIOException(
       
   430                         "Connection closed while receiving message");
       
   431                 }
       
   432                 //checking for valid permissions
       
   433                 ApplicationUtils appUtils = ApplicationUtils.getInstance();
       
   434                 MMSPermissionImpl permission = new MMSPermissionImpl("mms://*",
       
   435                         "receive");
       
   436                 appUtils.checkPermission(permission);
       
   437 
       
   438                 byte[] msg = _retrieveMessage(iNativeHandle);
       
   439                 rMsg = MultipartMessageImpl.deserialize(msg, getMMSMaxSize());
       
   440                 iMessagesOnQueue--;
       
   441             }
       
   442         }
       
   443         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   444                    "- MMSConnectionImpl::receive()");
       
   445         return rMsg;
       
   446     }
       
   447 
       
   448     /**
       
   449      * Sets the message listener for this connection
       
   450      *
       
   451      * @param aListener
       
   452      *            listener interested for incoming message.
       
   453      * @exceptions throws IOException if the connection is already closed or
       
   454      *             this method is called on a client connection.
       
   455      */
       
   456     public void setMessageListener(MessageListener aListener) throws IOException
       
   457     {
       
   458         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   459                    "+ MMSConnectionImpl::setMessageListener()");
       
   460         if (!iServerConnection)
       
   461         {
       
   462             throw new IOException(ExceptionStrings.CLIENT_MODE);
       
   463         }
       
   464         if (iState == CLOSED)
       
   465         {
       
   466             throw new IOException("Setting message listener failed: " +
       
   467                                   ExceptionStrings.CONNECTION_CLOSED);
       
   468         }
       
   469         iMessageListener = aListener;
       
   470         if (iMessageListener != null)
       
   471         {
       
   472             synchronized (iMessageLock)
       
   473             {
       
   474                 iMessageLock.notify();
       
   475             }
       
   476         }
       
   477         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   478                    "- MMSConnectionImpl::setMessageListener()");
       
   479     }
       
   480 
       
   481     /**
       
   482      * Method that validates the message attributes
       
   483      *
       
   484      * @exceptions Throws IOException if any of the attribute is not valid
       
   485      */
       
   486     private MultipartMessageImpl validateMessage(Message aMsg)
       
   487     throws IOException
       
   488     {
       
   489         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   490                    "+ MMSConnectionImpl::validateMessage()");
       
   491         // check against null
       
   492         if (null == aMsg)
       
   493         {
       
   494             throw new NullPointerException(ExceptionStrings.NULL_MESSAGE);
       
   495         }
       
   496 
       
   497         // make sure it is a MultipartMessageImpl
       
   498         MultipartMessageImpl mMsg;
       
   499         try
       
   500         {
       
   501             mMsg = (MultipartMessageImpl) aMsg;
       
   502         }
       
   503         catch (ClassCastException ex)
       
   504         {
       
   505             throw new IllegalArgumentException(ExceptionStrings.
       
   506                                                INVALID_MESSAGE_TYPE);
       
   507         }
       
   508 
       
   509         // check basic validation of the message and the corresponding parts
       
   510         if (!mMsg.iValidationDone)
       
   511         {
       
   512             // Forces the validation of the message if it hasn't been done
       
   513             // validation is done so that we reconstruct the message
       
   514             // with the eyes of the application and report any exceptions
       
   515             // to the application
       
   516             MultipartMessageImpl cloneMsg = new MultipartMessageImpl(
       
   517                 mMsg.getDestinationAddress(),
       
   518                 mMsg.getTimestamp() == null ? 0 : mMsg.getTimestamp().getTime(),
       
   519                 MmsPropertyRetriever.getMMSMaxSize());
       
   520 
       
   521             // first go through addresses and clone them for the new message
       
   522             cloneAddresses(MultipartMessageHeader.ADDRESS_TYPE_TO, cloneMsg,
       
   523                            mMsg);
       
   524             cloneAddresses(MultipartMessageHeader.ADDRESS_TYPE_BCC, cloneMsg,
       
   525                            mMsg);
       
   526             cloneAddresses(MultipartMessageHeader.ADDRESS_TYPE_CC, cloneMsg,
       
   527                            mMsg);
       
   528 
       
   529             // clone the headers
       
   530             cloneMsg.setHeader(MultipartMessageHeader.DELIVERY_TIME_HEADER,
       
   531                                mMsg.getHeader(MultipartMessageHeader.DELIVERY_TIME_HEADER));
       
   532             cloneMsg.setHeader(MultipartMessageHeader.PRIORITY_HEADER,
       
   533                                mMsg.getHeader(MultipartMessageHeader.PRIORITY_HEADER));
       
   534 
       
   535             // clone the message parts
       
   536             cloneMessageParts(cloneMsg, mMsg);
       
   537 
       
   538             // clone the startContentId
       
   539             cloneMsg.setStartContentId(mMsg.getStartContentId());
       
   540 
       
   541             // clone the subject
       
   542             cloneMsg.setSubject(mMsg.getSubject());
       
   543         }
       
   544 
       
   545         // make sure there are recipients
       
   546         if (isEmpty(mMsg.getAddresses(MultipartMessageHeader.ADDRESS_TYPE_TO))
       
   547                 && isEmpty(mMsg.getAddresses(MultipartMessageHeader.ADDRESS_TYPE_BCC))
       
   548                 && isEmpty(mMsg.getAddresses(MultipartMessageHeader.ADDRESS_TYPE_CC)))
       
   549         {
       
   550             throw new IllegalArgumentException(ExceptionStrings.NO_RECIPIENTS);
       
   551         }
       
   552 
       
   553         if (mMsg.iReply)
       
   554         {
       
   555             // reset the delivery time
       
   556             mMsg.setHeader(MultipartMessageHeader.DELIVERY_TIME_HEADER, null);
       
   557             // if this message does not have the replyToAppid, it means it came
       
   558             // from a client connection and we can not reply
       
   559             if (mMsg.getReplyToAppID() == null ||(mMsg.getReplyToAppID() != null
       
   560                                                   && (mMsg.getReplyToAppID().length() == 0 || mMsg.getReplyToAppID()
       
   561                                                       .equals(MultipartMessageHeader.DUMMY_REPLY_TO_APP_ID))))
       
   562             {
       
   563                 throw new IllegalArgumentException(ExceptionStrings.
       
   564                                                    CLIENT_MESSAGE);
       
   565             }
       
   566             String dest = mMsg.getAddress();
       
   567             mMsg.removeAddresses();
       
   568             // replace applicationID with replyToAppID
       
   569             mMsg.setAddress(dest);
       
   570         }
       
   571         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   572                    "- MMSConnectionImpl::validateMessage()");
       
   573         return mMsg;
       
   574     }
       
   575 
       
   576     private void cloneAddresses(String aAddressType,
       
   577                                 MultipartMessageImpl aDestMsg, MultipartMessageImpl aSourceMsg)
       
   578     {
       
   579         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   580                    "+ MMSConnectionImpl::cloneAddresses()");
       
   581         String[] addresses = aSourceMsg.getAddresses(aAddressType);
       
   582         if (addresses != null)
       
   583         {
       
   584             for (int i = 0; i < addresses.length; i++)
       
   585             {
       
   586                 aDestMsg.addAddress(aAddressType, addresses[i]);
       
   587             }
       
   588         }
       
   589         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   590                    "- MMSConnectionImpl::cloneAddresses()");
       
   591     }
       
   592 
       
   593     private void cloneMessageParts(MultipartMessageImpl aDestMsg,
       
   594                                    MultipartMessageImpl aSourceMsg) throws SizeExceededException
       
   595     {
       
   596         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   597                    "+ MMSConnectionImpl::cloneMessageParts()");
       
   598         MessagePart[] parts = aSourceMsg.getMessageParts();
       
   599         if (parts != null)
       
   600         {
       
   601             for (int i = 0; i < parts.length; i++)
       
   602             {
       
   603                 MessagePart part = parts[i];
       
   604                 aDestMsg.addMessagePart(new MessagePart(part.getContent(),
       
   605                                                         part.getMIMEType(), part.getContentID(),
       
   606                                                         part.getContentLocation(), part.getEncoding()));
       
   607             }
       
   608         }
       
   609         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   610                    "- MMSConnectionImpl::cloneMessageParts()");
       
   611     }
       
   612 
       
   613     /**
       
   614      * Check that the address that has been provided when this connection was
       
   615      * created is still among the "to" recipients
       
   616      */
       
   617     private void validateClientMessage(MultipartMessageImpl aMsg)
       
   618     {
       
   619         // sets the replyToAppID to its own iAppID
       
   620         aMsg.setReplyToAppID(MultipartMessageHeader.DUMMY_REPLY_TO_APP_ID);
       
   621     }
       
   622 
       
   623     /**
       
   624      * Method used for checking if there are no recipients set for * a message
       
   625      * to be set
       
   626      */
       
   627     private boolean isEmpty(String[] aArray)
       
   628     {
       
   629         if (aArray == null || (aArray != null && aArray.length == 0))
       
   630         {
       
   631             return true;
       
   632         }
       
   633         return false;
       
   634     }
       
   635 
       
   636     /**
       
   637      * Method that ensures whether a connection is opened
       
   638      *
       
   639      * @exceptions Throws IOException if the connection is in closed state
       
   640      */
       
   641     private void ensureOpen() throws IOException
       
   642     {
       
   643         synchronized (iCloseLock)
       
   644         {
       
   645             if (iState == CLOSED)
       
   646             {
       
   647                 throw new IOException(ExceptionStrings.CONNECTION_CLOSED);
       
   648             }
       
   649         }
       
   650     }
       
   651 
       
   652     /**
       
   653      * Callback through which the Native notifies about the receiving of a
       
   654      * Message or any error while receiving a message
       
   655      *
       
   656      * @param1  aReceivedMesgs - number of messages to be received
       
   657      *
       
   658      */
       
   659     protected int messageReceiveCallback(int aReceivedMesgs)
       
   660     {
       
   661         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   662                    "+ MMSConnectionImpl::messageReceiveCallback()");
       
   663         synchronized (iMessageLock)
       
   664         {
       
   665             if ((!iMessageWaiting) && (null == iMessageListener))
       
   666             {
       
   667                 try
       
   668                 {
       
   669                     iMessageLock.wait();
       
   670                 }
       
   671                 catch (InterruptedException e)
       
   672                 {
       
   673                     Logger.ELOG(Logger.EWMA, "Receiving a callback failed", e);
       
   674                 }
       
   675             }
       
   676         }
       
   677         synchronized (iReadLock)
       
   678         {
       
   679             if (aReceivedMesgs >= 0)
       
   680             {
       
   681                 iMessagesOnQueue += aReceivedMesgs;
       
   682                 iNotificationsToMake += aReceivedMesgs;
       
   683             }
       
   684             if (iMessageWaiting)
       
   685             {
       
   686                 iMessageWaiting = false;
       
   687                 //if a receive operation was called notify the receive about
       
   688                 //the incoming message
       
   689                 iReadLock.notify();
       
   690 
       
   691             }
       
   692             else if (iMessageListener != null)
       
   693             {
       
   694                 while (iNotificationsToMake > 0)
       
   695                 {
       
   696                     iMessageListener.notifyIncomingMessage(this);
       
   697                     iNotificationsToMake--;
       
   698                 }
       
   699             }
       
   700         }
       
   701         Logger.LOG(Logger.EWMA, Logger.EInfo,
       
   702                    "- MMSConnectionImpl::messageReceiveCallback()");
       
   703         return ((iState == CLOSED)? -1 : 0);
       
   704     }
       
   705 
       
   706     private int getRecipientsCount(MultipartMessageImpl mMsg)
       
   707     {
       
   708         int cnt = 0;
       
   709         String[] tmp = mMsg.getAddresses(
       
   710                            MultipartMessageHeader.ADDRESS_TYPE_TO);
       
   711         if (tmp != null)
       
   712         {
       
   713             cnt += tmp.length;
       
   714         }
       
   715         tmp = mMsg.getAddresses(
       
   716                   MultipartMessageHeader.ADDRESS_TYPE_CC);
       
   717         if (tmp != null)
       
   718         {
       
   719             cnt += tmp.length;
       
   720         }
       
   721         tmp = mMsg.getAddresses(
       
   722                   MultipartMessageHeader.ADDRESS_TYPE_BCC);
       
   723         if (tmp != null)
       
   724         {
       
   725             cnt += tmp.length;
       
   726         }
       
   727         return cnt;
       
   728     }
       
   729 
       
   730     private native int _createPeer(boolean aServerConnection, String aUri);
       
   731 
       
   732     private native void _openConnection(int aNativeHandle);
       
   733 
       
   734     private native int _send(byte[] aMsg, int aOffset, int aMsgLength,
       
   735                              String aAddress, int aNativeHandle);
       
   736 
       
   737     private native byte[] _retrieveMessage(int aNativeHandle);
       
   738 
       
   739     private native void _closeConnection(int aNativeHandle);
       
   740 
       
   741     private native void _dispose(int aNativeHandle);
       
   742 
       
   743     private native void _checkError(int aError);
       
   744 }
       
   745 
       
   746