018d56addf14db7f38c55d6c5871c46e5ad5bb62
[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    test::Response a_response;   
46    test::Request a_request;
47    comm::INetAddress a_inetAddress;
48    Recycler <comm::ClientSocket, ClientSocketAllocator> a_clientSockets;
49
50    void do_initialize () throw (RuntimeException);
51    
52    void eventReceiveMessage (comm::ClientSocket&, const comm::Message&) throw (RuntimeException);
53    void eventBreakConnection (const comm::ClientSocket&) throw ();
54    void eventUser (const char* id, const void* context) throw ();   
55 };
56
57 class KXClient : public anna::comm::Application {
58 public:
59    KXClient ();
60       
61    const test::Menu& getMenu () const throw () { return a_menu; }
62    
63 private:
64    MyCommunicator a_communicator;
65    test::Menu a_menu;
66
67    void initialize () throw (RuntimeException);
68    void run () throw (RuntimeException);    
69 };
70
71 using namespace std;
72 using namespace test;
73
74 comm::INetAddress* MyCommunicator::ClientSocketAllocator::st_inetAddress = NULL;
75
76 int main (int argc, const char** argv)
77 {
78    CommandLine& commandLine (CommandLine::instantiate ());
79    KXClient app;
80    
81    try {
82       commandLine.initialize (argv, argc);
83       commandLine.verify ();
84
85       Logger::setLevel (Logger::Debug); 
86       Logger::initialize ("kclient", new TraceWriter ("file.trace", 4096000));
87  
88       app.start ();
89    }
90    catch (Exception& ex) {
91       cout << ex.asString () << endl;
92    }
93    
94    return 0;
95 }
96
97 KXClient::KXClient () : 
98    Application ("kclient", "KXClient", "1.0.0"),
99    a_menu (&a_communicator)
100 {
101    CommandLine& commandLine (CommandLine::instantiate ());
102       
103    commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas.");
104    commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccion IP Puerto en el que el servidor atiende respuestas.");
105 }
106
107 void KXClient::initialize () 
108    throw (RuntimeException)
109 {
110    a_communicator.attach (&a_menu);
111 }
112
113 void KXClient::run ()
114    throw (RuntimeException)
115 {   
116    a_menu.paint ();
117    a_communicator.accept ();
118 }
119
120 //--------------------------------------------------------------------------------------------
121 // Crea la direccion a la que se conectaran los ClientSocket para enviar las peticiones.
122 //--------------------------------------------------------------------------------------------
123 void MyCommunicator::do_initialize () 
124    throw (RuntimeException)
125 {
126    CommandLine& cl (CommandLine::instantiate ());    
127
128    using namespace anna::comm;
129
130    Network& network = Network::instantiate ();
131    
132    Device* device = network.find (Device::asAddress (cl.getValue ("a")));
133    
134    a_inetAddress.setAddress (device);
135    a_inetAddress.setPort (cl.getIntegerValue ("p"));
136    
137    ClientSocketAllocator::st_inetAddress = &a_inetAddress;
138 }
139
140 void MyCommunicator::eventReceiveMessage (comm::ClientSocket&, const comm::Message& message)
141    throw (RuntimeException)
142 {
143    a_response.decode (message.getBody ());
144    
145    cout << endl << "Resultado de la peticion: " << a_response.x << (char) a_response.op << a_response.y  << " = " << a_response.result << endl << endl;
146    
147    static_cast <KXClient&> (anna::comm::functions::getApp ()).getMenu ().paint ();
148 }
149
150 //-----------------------------------------------------------------------------------------
151 // Cuando el servidor remoto cierra el socket => debemos liberar este extremo para poder
152 // reutilizar la instancia (no la conexion).
153 //-----------------------------------------------------------------------------------------
154 void MyCommunicator::eventBreakConnection (const comm::ClientSocket& clientSocket) 
155    throw ()
156 {
157    a_clientSockets.release (&clientSocket);
158 }
159
160 //-----------------------------------------------------------------------------------------
161 // Cuando el Menu tiene disponibles todos los datos necesarios para la peticiĆ³n se lo
162 // notifica al comunicador mediante un evento de usuario.
163 //-----------------------------------------------------------------------------------------
164 void MyCommunicator::eventUser (const char* id, const void* context) 
165    throw ()
166 {
167    LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventUser", ANNA_FILE_LOCATION));
168
169    if (anna_strcmp (id, Menu::EventData) == 0) {
170       const Menu::Data* data (reinterpret_cast <const Menu::Data*>  (context));
171       
172       a_request.op = data->a_operation;
173       a_request.x = data->a_op1;
174       a_request.y = data->a_op2;
175       
176       comm::ClientSocket* clientSocket = a_clientSockets.create ();
177             
178       try {
179          attach (clientSocket);
180          clientSocket->send (a_request);
181       }
182       catch (RuntimeException& ex) {
183          a_clientSockets.release (clientSocket);
184          ex.trace ();
185       }
186    } 
187 }