tizen 2.4 release
[framework/web/wrt-commons.git] / modules / rpc / include / dpl / rpc / generic_socket_rpc_client.h
1 /*
2  * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  *    Licensed under the Apache License, Version 2.0 (the "License");
5  *    you may not use this file except in compliance with the License.
6  *    You may obtain a copy of the License at
7  *
8  *        http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *    Unless required by applicable law or agreed to in writing, software
11  *    distributed under the License is distributed on an "AS IS" BASIS,
12  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *    See the License for the specific language governing permissions and
14  *    limitations under the License.
15  */
16 /*
17  * @file        generic_socket_rpc_client.h
18  * @author      Przemyslaw Dobrowolski (p.dobrowolsk@samsung.com)
19  * @version     1.0
20  * @brief       This file is the header file for generic socket RPC client
21  */
22 #ifndef DPL_GENERIC_SOCKET_RPC_CLIENT_H
23 #define DPL_GENERIC_SOCKET_RPC_CLIENT_H
24
25 #include <dpl/rpc/abstract_rpc_connector.h>
26 #include <dpl/socket/abstract_socket.h>
27 #include <set>
28
29 namespace DPL {
30 namespace RPC {
31 template<typename SocketType>
32 class GenericSocketRPCClient :
33     public AbstractRPCConnector,
34     private DPL::Event::EventListener<DPL::Socket::AbstractSocketEvents::
35                                           ConnectedEvent>
36 {
37   public:
38     class Exception
39     {
40       public:
41         DECLARE_EXCEPTION_TYPE(DPL::Exception, Base)
42         DECLARE_EXCEPTION_TYPE(Base, OpenFailed)
43         DECLARE_EXCEPTION_TYPE(Base, CloseFailed)
44     };
45
46   protected:
47     // Derived class implementations for connection managment
48     virtual AbstractRPCConnection *OpenSpecificConnection(SocketType *socket) =
49         0;
50
51   private:
52     typedef std::set<SocketType *> InternalConnectionSet;
53     InternalConnectionSet m_internalConnectionSet;
54
55     virtual void OnEventReceived(
56         const DPL::Socket::AbstractSocketEvents::ConnectedEvent &event)
57     {
58         // Retrieve socket sender
59         SocketType *socket = static_cast<SocketType *>(event.GetSender());
60
61         WrtLogD("Connection with RPC server established");
62
63         // Is this connection still tracked ?
64         // It might have disappeared on close
65         typename InternalConnectionSet::iterator iterator =
66             m_internalConnectionSet.find(socket);
67
68         if (iterator == m_internalConnectionSet.end()) {
69             WrtLogD("RPC client connection socket disappeared");
70             return;
71         }
72
73         // Open specific connection implementation
74         AbstractRPCConnection *connection = OpenSpecificConnection(socket);
75
76         // Remove internal connection
77         socket->EventSupport<DPL::Socket::AbstractSocketEvents::ConnectedEvent>
78             ::RemoveListener(this);
79         m_internalConnectionSet.erase(iterator);
80
81         // Retrieve ID once again
82         AbstractRPCConnectionID connectionID =
83             static_cast<AbstractRPCConnectionID>(socket);
84
85         // Inform listeners
86         DPL::Event::EventSupport<AbstractRPCConnectorEvents::
87                                      ConnectionEstablishedEvent>::
88             EmitEvent(AbstractRPCConnectorEvents::ConnectionEstablishedEvent(
89                           connectionID, connection, EventSender(
90                               this)), DPL::Event::EmitMode::Queued);
91     }
92
93   public:
94     explicit GenericSocketRPCClient()
95     {}
96
97     virtual ~GenericSocketRPCClient()
98     {
99         // Always close all connections
100         CloseAll();
101     }
102
103     AbstractRPCConnectionID Open(const Address &socketAddress)
104     {
105         WrtLogD("Starting client: %s", socketAddress.ToString().c_str());
106
107         // Alloc new socket
108         SocketType *socket = new SocketType();
109
110         // Add socket listeners
111         socket->EventSupport<DPL::Socket::AbstractSocketEvents::ConnectedEvent>
112             ::AddListener(this);
113
114         Try
115         {
116             // Open socket
117             socket->Open();
118
119             // Start connecting to server
120             socket->Connect(Address(socketAddress));
121         }
122         Catch(DPL::Socket::AbstractSocket::Exception::Base)
123         {
124             // Remove back socket listener
125             socket->EventSupport<DPL::Socket::AbstractSocketEvents::
126                                      ConnectedEvent>::RemoveListener(this);
127
128             // Log debug message
129             WrtLogD("Cannot connect to: %s", socketAddress.ToString().c_str());
130
131             // Problem with client startup
132             ReThrowMsg(typename Exception::OpenFailed, socketAddress.ToString());
133         }
134
135         // Register new internal connection
136         m_internalConnectionSet.insert(socket);
137
138         // Debug info
139         WrtLogD(
140             "Client started on interface: %s",
141             socket->GetLocalAddress().ToString().c_str());
142
143         // Return unique identifier
144         return static_cast<AbstractRPCConnectionID>(socket);
145     }
146
147     void Close(AbstractRPCConnectionID connectionID)
148     {
149         WrtLogD("Closing client interface...");
150
151         // Get socket from ID
152         SocketType *socket = static_cast<SocketType *>(connectionID);
153
154         // Find corresponding internal connection
155         typename InternalConnectionSet::iterator iterator =
156             m_internalConnectionSet.find(socket);
157
158         if (iterator == m_internalConnectionSet.end()) {
159             return;
160         }
161
162         // Close socket
163         socket->Close();
164
165         // Remove internal socket
166         socket->EventSupport<DPL::Socket::AbstractSocketEvents::ConnectedEvent>
167             ::RemoveListener(this);
168         delete socket;
169
170         m_internalConnectionSet.erase(iterator);
171
172         // Done
173         WrtLogD("Closed");
174     }
175
176     void CloseAll()
177     {
178         while (!m_internalConnectionSet.empty()) {
179             Close(static_cast<AbstractRPCConnectionID>(*m_internalConnectionSet
180                                                            .begin()));
181         }
182     }
183 };
184 }
185 } // namespace DPL
186
187 #endif // DPL_GENERIC_SOCKET_RPC_CLIENT_H