87bf3c62349442c62f4d4b8bb5fdd5f306f927f8
[anna.git] / example / comm / kxClient / main.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 /*
10    Establece un manejador externo para controlar el teclado, recoge los parametros de la operacion
11    por este y envia la peticion al servidor que devolvera el resultado de aplicar la operacion 
12    sobre los parametros recogidos.
13
14    Este proceso, a diferencia de kclient, abre una nueva conexion por cada peticion que tiene que lanzar.
15
16    El cliente de esta aplicacion es: server.p => Transporte: comm::Transport.
17 */
18 #include <iostream>
19
20 #include <string.h>
21
22 #include <anna/core/core.hpp>
23
24 #include <anna/comm/Application.hpp>
25 #include <anna/comm/Communicator.hpp>
26 #include <anna/comm/INetAddress.hpp>
27 #include <anna/comm/ClientSocket.hpp>
28 #include <anna/comm/Network.hpp>
29 #include <anna/comm/Device.hpp>
30
31 #include <anna/test/Menu.hpp>
32 #include <anna/test/Request.hpp>
33 #include <anna/test/Response.hpp>
34
35 class MyCommunicator : public comm::Communicator {
36 public:   
37    class ClientSocketAllocator {
38    public:
39       static comm::INetAddress* st_inetAddress;      
40       static comm::ClientSocket* create ()  throw () { return new comm::ClientSocket (*st_inetAddress); }
41       static void destroy (comm::ClientSocket* clientSocket) throw () { delete clientSocket; }
42    };   
43    
44 private:
45    using comm::Communicator::eventBreakConnection;
46
47    test::Response a_response;   
48    test::Request a_request;
49    comm::INetAddress a_inetAddress;
50    Recycler <comm::ClientSocket, ClientSocketAllocator> a_clientSockets;
51
52    void do_initialize () throw (RuntimeException);
53    
54    void eventReceiveMessage (comm::ClientSocket&, const comm::Message&) throw (RuntimeException);
55    void eventBreakConnection (const comm::ClientSocket&) throw ();
56    void eventUser (const char* id, const void* context) throw ();   
57 };
58
59 class KXClient : public anna::comm::Application {
60 public:
61    KXClient ();
62       
63    const test::Menu& getMenu () const throw () { return a_menu; }
64    
65 private:
66    MyCommunicator a_communicator;
67    test::Menu a_menu;
68
69    void initialize () throw (RuntimeException);
70    void run () throw (RuntimeException);    
71 };
72
73 using namespace std;
74 using namespace test;
75
76 comm::INetAddress* MyCommunicator::ClientSocketAllocator::st_inetAddress = NULL;
77
78 int main (int argc, const char** argv)
79 {
80    CommandLine& commandLine (CommandLine::instantiate ());
81    KXClient app;
82    
83    try {
84       commandLine.initialize (argv, argc);
85       commandLine.verify ();
86
87       Logger::setLevel (Logger::Debug); 
88       Logger::initialize ("kclient", new TraceWriter ("file.trace", 4096000));
89  
90       app.start ();
91    }
92    catch (Exception& ex) {
93       cout << ex.asString () << endl;
94    }
95    
96    return 0;
97 }
98
99 KXClient::KXClient () : 
100    Application ("kclient", "KXClient", "1.0.0"),
101    a_menu (&a_communicator)
102 {
103    CommandLine& commandLine (CommandLine::instantiate ());
104       
105    commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas.");
106    commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccion IP Puerto en el que el servidor atiende respuestas.");
107 }
108
109 void KXClient::initialize () 
110    throw (RuntimeException)
111 {
112    a_communicator.attach (&a_menu);
113 }
114
115 void KXClient::run ()
116    throw (RuntimeException)
117 {   
118    a_menu.paint ();
119    a_communicator.accept ();
120 }
121
122 //--------------------------------------------------------------------------------------------
123 // Crea la direccion a la que se conectaran los ClientSocket para enviar las peticiones.
124 //--------------------------------------------------------------------------------------------
125 void MyCommunicator::do_initialize () 
126    throw (RuntimeException)
127 {
128    CommandLine& cl (CommandLine::instantiate ());    
129
130    using namespace anna::comm;
131
132    Network& network = Network::instantiate ();
133    
134    Device* device = network.find (Device::asAddress (cl.getValue ("a")));
135    
136    a_inetAddress.setAddress (device);
137    a_inetAddress.setPort (cl.getIntegerValue ("p"));
138    
139    ClientSocketAllocator::st_inetAddress = &a_inetAddress;
140 }
141
142 void MyCommunicator::eventReceiveMessage (comm::ClientSocket&, const comm::Message& message)
143    throw (RuntimeException)
144 {
145    a_response.decode (message.getBody ());
146    
147    cout << endl << "Resultado de la peticion: " << a_response.x << (char) a_response.op << a_response.y  << " = " << a_response.result << endl << endl;
148    
149    static_cast <KXClient&> (anna::comm::functions::getApp ()).getMenu ().paint ();
150 }
151
152 //-----------------------------------------------------------------------------------------
153 // Cuando el servidor remoto cierra el socket => debemos liberar este extremo para poder
154 // reutilizar la instancia (no la conexion).
155 //-----------------------------------------------------------------------------------------
156 void MyCommunicator::eventBreakConnection (const comm::ClientSocket& clientSocket) 
157    throw ()
158 {
159    a_clientSockets.release (&clientSocket);
160 }
161
162 //-----------------------------------------------------------------------------------------
163 // Cuando el Menu tiene disponibles todos los datos necesarios para la peticiĆ³n se lo
164 // notifica al comunicador mediante un evento de usuario.
165 //-----------------------------------------------------------------------------------------
166 void MyCommunicator::eventUser (const char* id, const void* context) 
167    throw ()
168 {
169    LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventUser", ANNA_FILE_LOCATION));
170
171    if (anna_strcmp (id, Menu::EventData) == 0) {
172       const Menu::Data* data (reinterpret_cast <const Menu::Data*>  (context));
173       
174       a_request.op = data->a_operation;
175       a_request.x = data->a_op1;
176       a_request.y = data->a_op2;
177       
178       comm::ClientSocket* clientSocket = a_clientSockets.create ();
179             
180       try {
181          attach (clientSocket);
182          clientSocket->send (a_request);
183       }
184       catch (RuntimeException& ex) {
185          a_clientSockets.release (clientSocket);
186          ex.trace ();
187       }
188    } 
189 }