javacommons/comms/inc/commsendpoint.h
branchRCL_3
changeset 19 04becd199f91
child 87 1627c337e51e
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/javacommons/comms/inc/commsendpoint.h	Tue Apr 27 16:30:29 2010 +0300
@@ -0,0 +1,346 @@
+/*
+* Copyright (c) 2008 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  This is an abstract base class for Comms endpoints.
+*
+*/
+
+#ifndef COMMSENDPOINT_H
+#define COMMSENDPOINT_H
+
+#include <pthread.h>
+#include <map>
+#include <jni.h>
+
+#include "javaosheaders.h"
+#include "scopedlocks.h"
+
+#include "transport.h"
+
+namespace java
+{
+namespace comms
+{
+
+class CommsMessage;
+class CommsListener;
+
+class ListenerWrapper;
+
+/**
+* This is an abstract base class for Comms endpoints. It provides implementation for
+* registering listeners and for synchronous message sending.
+*
+* Comms endpoint provides interprocess communication functionality. Comms communication
+* is point-to-point meaning that client endpoint can be connected to a single server at a time.
+* Communication is message based, where users wrap their payload to CommsMessage.
+* Comms endpoints support synchronous and asynchronous message sending.
+*
+* Messages can be sent asynchronously or synchronously. Synchronous message sending blocks until
+* a reply is received or when specified timeout occurs.
+*
+* CommsListener provides a way to receive messages asynchronously. Listeners are registered
+* to endpoint. When message belonging to listener is received, will Comms endpoint make a
+* callback for listener. Application can register as many listeners as need.
+*
+* Application can register also a default listener, which gets called if there is no registered
+* listener for received message.
+*
+* CommsEndpoint is thread safe.
+*
+* Usage:
+* It is recomended that at least default listener is registered before CommsServerEndpoint
+* is started. This ensures that no messages are lost.
+* @code
+* CommsServerEndpoint comms;
+* comms.registerDefaultListener(listener);
+* comms.start(MY_SERVER_NAME);
+* ...
+* comms.stop();
+* @endcode
+*/
+
+/**
+* This constant can be used when timeout functionality of synchronous sendReceive is not needed.
+* SendReceive method will return when reply is received or when connection is closed.
+* @see CommsEndpoint::sendReceive()
+*/
+const int WAIT_FOR_EVER = -1;
+
+class CommsEndpoint : public IpcListener
+{
+public:
+    /**
+    * A constructor.
+    */
+    OS_IMPORT CommsEndpoint();
+
+    /**
+    * A destructor.
+    */
+    OS_IMPORT virtual ~CommsEndpoint();
+
+    /**
+    * Registers message handler for given module id.
+    * CommsListener provides a way to receive messages asynchronously.
+    * Module id identifies to which component message belongs. Every message will contain module id
+    * information that is used to route message to correct listener.
+    *
+    * There can be one registered listener for each module id and same listener can be registered
+    * for multiple module ids.
+    *
+    * Listener registration remains valid during connect/disconnect and start/stop.
+    * @code
+    * CommsClientEndpoint comms;
+    * comms.registerListener(MODULE_ID_A, listenerA);
+    * comms.registerListener(MODULE_ID_B, listenerB);
+    * comms.connect(MY_SERVER_NAME);
+    * @endcode
+    * @param[in] aModuleId Module id, messages with that module id are forwarded to given listener
+    * @param[in] aListener Listener that will be called when message with matching module id is received
+    * @see unregisterListener()
+    * @see send()
+    * @return 0 in success, errno in failure
+    */
+    OS_IMPORT virtual int registerListener(int aModuleId, CommsListener* aListener);
+
+    /**
+    * Unregisters message handler for given module id.
+    * @code
+    * CommsClientEndpoint comms;
+    * comms.registerListener(MODULE_ID_A, listenerA);
+    * comms.unregisterListener(MODULE_ID_A, listenerA);
+    * @endcode
+    * @param[in] aModuleId Module id, identifies listener that will be removed
+    * @param[in] aListener Listener that will be removed
+    * @see unregisterListener()
+    * @see send()
+    * @return 0 in success, errno in failure
+    */
+    OS_IMPORT virtual int unregisterListener(int aModuleId, CommsListener* aListener);
+
+    /**
+    * Registers default listener.
+    * There can be only one default listener. Default listener is called if there is no registered listener for received message.
+    * If there is no default listener then received messages without listener will be discarded.
+    * @param[in] aDefaultListener Default message handler that will be called if no other suitable handlers are found
+    * @see unregisterDefaultListener()
+    * @return 0 in success, errno in failure
+    */
+    OS_IMPORT   virtual int registerDefaultListener(CommsListener* aDefaultListener);
+
+    /**
+    * Unregisters default listener.
+    * @param[in] aDefaultListener Listener that will be removed
+    * @see registerDefaultListener()
+    * @return 0 in success, errno in failure
+    */
+    OS_IMPORT virtual int unregisterDefaultListener(CommsListener* aDefaultListener);
+
+    /**
+    * Sends a message.
+    * Message recipient must set by CommsMessage::setReceiver() method. It is important that
+    * message header is properly filled because header information is used in message routing.
+    * @code
+    * CommsMessage msg;
+    *
+    * // set the headers
+    * msg.setMessageId(MY_MESSAGE_ID);
+    * msg.setModuleId(MY_MODULE_ID);
+    * msg.setReceiver(CLIENT_ADDRESS);
+    *
+    * // set the payload
+    * msg << "my payload";
+    *
+    * // send message
+    * int rc = comms.send(msg);
+    * @endcode
+    * @param[in] aMessage A message to be sent
+    * @see sendReceive()
+    * @see registerListener()
+    * @return 0 in success, errno in failure
+    */
+    OS_IMPORT virtual int send(CommsMessage& aMessage) = 0;
+
+    /**
+    * Sends and receives message syncronously.
+    * Method blocks until response message is received or timeout expires.
+    * Message recipient must set by CommsMessage::setReceiver() method. It is important that
+    * message header is properly filled because header information is used in message routing.
+    * @code
+    * CommsMessage msg;
+    *
+    * // set the headers
+    * msg.setMessageId(MY_MESSAGE_ID);
+    * msg.setModuleId(MY_MODULE_ID);
+    *
+    * CommsMessage receivedMessage;
+    * int timeout = 10; //10s
+    *
+    * // send and receive message
+    * int rc = comms.sendReceive(msg, receivedMessage, timeout);
+    * if(rc!=0)
+    * {
+    * LOG("sendReceive failed");
+    * return;
+    * }
+    * int i;
+    * receivedMessage >> i;
+    * @endcode
+    * @param[in] aMessage A message to be sent
+    * @param[out] aReceivedMessage Received message (message content will be empy if method call fails)
+    * @param[in] aTimeoutInSecs Timeout in seconds for how long reply is waited
+    * @see send()
+    * @return 0 in success
+    * @return errno in failure and timeout cases
+    */
+    OS_IMPORT virtual int sendReceive(CommsMessage& aMessage, CommsMessage& aReceivedMessage, int aTimeoutInSecs);
+
+protected:
+    /**
+    * Routes received message to waiting sendReceive thread or message listener
+    * @param[in] aMessage Received message
+    * @see -
+    * @return -
+    */
+    OS_IMPORT virtual void handleIpcMessage(CommsMessage& aMessage);
+
+    /**
+    * Dispatches received message to listener or default listener
+    * @param[in] aMessage Received message
+    * @see -
+    * @return 0 in success, errno in failure
+    */
+    OS_IMPORT virtual int handleMessage(CommsMessage& aMessage);
+
+    /**
+    * Generates unique message reference
+    * @return message reference
+    */
+    OS_IMPORT virtual int generateMessageReference();
+
+    // IpcListener methods
+    /**
+    * Callback that is called when underlaying transport stack receives a message
+    * Called in the context of message loop thread.
+    * @param[out] aMsg Received message
+    * @return -
+    */
+    OS_IMPORT virtual void processMessage(const ipcMessage_t* aMsg);
+    /**
+    * Callback that is called when underlaying transport stack's message loop thread starts.
+    * Called in the context of message loop thread.
+    * @param -
+    * @return -
+    */
+    OS_IMPORT virtual void onStart();
+    /**
+    * Callback that is called when underlaying transport stack's message loop thread exits.
+    * Called in the context of message loop thread.
+    * @param -
+    * @return -
+    */
+    OS_IMPORT virtual void onExit();
+
+private:
+    ListenerWrapper* mDefaultListener;
+
+    typedef std::map<const int, ListenerWrapper*> listeners_t;
+    listeners_t mListeners;
+    java::util::ScopedMutex mListenersMutex;
+
+    int mMessageRefCounter;
+    java::util::ScopedMutex mMessageRefMutex;
+
+    // sendReceive related stuff
+    int isSendReceiveMessage(CommsMessage& message);
+
+    typedef struct sendReceiveMessage_s
+    {
+        CommsMessage*   p_message;
+        int*            p_done;
+        int*            p_result;
+    } sendReceiveMessage_t;
+
+    typedef std::map<int, sendReceiveMessage_t> sendReceiveListeners_t;
+    sendReceiveListeners_t mSendReceiveListeners; // access protected by mSendReceiveMutex
+
+    pthread_mutex_t mSendReceiveMutex;
+    pthread_cond_t  mSendReceiveCondition;
+
+public:
+    /**
+    * Registers Java message handler for given module id.
+    * @param[in] aModuleId Module id, messages with that module id are forwarded to given listener
+    * @param[in] aListener Listener that will be called when message with matching module id is received
+    * @param[in] aEnv JNI context
+    * @see unregisterJavaListener()
+    * @return 0 in success, errno in failure
+    */
+    OS_IMPORT virtual int registerJavaListener(int aModuleId, jobject aListener, JNIEnv* aEnv);
+
+    /**
+    * Unregisters Java message handler for given module id.
+    * @param[in] aModuleId Module id
+    * @param[in] aListener Listener to be removed
+    * @param[in] aEnv JNI context
+    * @see registerJavaListener()
+    * @return 0 in success, errno in failure
+    */
+    OS_IMPORT virtual int unregisterJavaListener(int aModuleId, jobject aListener, JNIEnv* aEnv);
+
+    /**
+    * Registers default listener.
+    * There can be only one default listener. Default listener is called if there is no registered listener for received message.
+    * If there is no default listener then received messages without listener will be discarded.
+    * @param[in] aDefaultListener Default message handler
+    * @see unregisterDefaultJavaListener()
+    * @return 0 in success, errno in failure
+    */
+    OS_IMPORT virtual int registerDefaultJavaListener(jobject aListener, JNIEnv* aEnv);
+
+    /**
+    * Unregisters default listener.
+    * @param[in] aDefaultListener Listener that will be removed
+    * @see registerDefaultJavaListener()
+    * @return 0 in success, errno in failure
+    */
+    OS_IMPORT virtual int unregisterDefaultJavaListener(jobject aListener, JNIEnv* aEnv);
+
+    /**
+    * Attach internal message loop thread to JVM.
+    * @param[in] aEnv JNI context
+    * @see detachFromVm
+    * @return 0 in success, errno in failure
+    */
+    OS_IMPORT virtual int attachToVm(JNIEnv* aEnv);
+
+    /**
+    * Detach internal message loop thread from JVM.
+    * @param -
+    * @see attachToVm
+    * @return 0 in success, errno in failure
+    */
+    OS_IMPORT virtual int detachFromVm();
+
+protected:
+    JavaVM* mVm;
+    JNIEnv* mJNIEnv;
+
+};
+
+} // namespace comms
+} // namespace java
+
+
+#endif // COMMSENDPOINT_H