e348d5d140eff617b3e406506f5c19c03e14d758
[anna.git] / example / comm / datagramRServer / 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   Ejemplo de programa servidor. Atiende peticiones aritmeticas, el protocolo de transporte
11   sera el comm::Transport y el contenido del mensaje sera el resutaldo de un comm::Codec con los
12   (x, y, op) -> El resultado sera estos tres componente mas result.
13   
14   Ejemplo de uso del sistema de receiveres, que son capaces de tratar N peticiones de forma
15   totalmetne simultanea en caso de estar en un entorno MT.
16
17   Para poder probar el sistema de congestion se puede indicar un numero de milisegundos de 
18   retardo aplicados a cada contestacion.
19
20   Los clientes pueden ser: client.p o kclient.p
21 */
22 #include <iostream>
23
24 #include <anna/core/core.hpp>
25 #include <anna/comm/comm.hpp>
26
27 #include <anna/xml/Node.hpp>
28 #include <anna/xml/Attribute.hpp>
29
30 #include <anna/app/functions.hpp>
31
32 #include <anna/test/Request.hpp>
33 #include <anna/test/Response.hpp>
34 #include <anna/test/Communicator.hpp>
35
36 using namespace std;
37 using namespace test;
38
39 class MyCommunicator : public test::Communicator {
40 public:
41    MyCommunicator () :  test::Communicator () {;}
42 };
43
44 class MyReceiver : public Receiver {
45 public:
46    static const char* className () throw () { return "MyReceiver"; }
47
48 private:
49    Request a_request;
50    Response a_response;
51    MyCommunicator* a_communicator;
52    
53    MyReceiver () : Receiver ("MyReceiver") { ; }
54    void initialize () throw (RuntimeException);
55    void apply (comm::ClientSocket &, const Message&) throw (RuntimeException);
56    
57    friend class Allocator <MyReceiver>;      
58 };
59
60 class ArithmeticServer : public comm::Application {
61 public:
62    ArithmeticServer ();
63
64    comm::DatagramSocket* getOutput () throw () { return a_output; }
65       
66 private:
67    MyCommunicator* a_communicator;
68    ReceiverFactoryImpl <MyReceiver> a_receiverFactory;
69    comm::DatagramSocket* a_input;
70    comm::DatagramSocket* a_output;
71
72    void initialize () throw (RuntimeException);
73    void run () throw (RuntimeException);
74    xml::Node* asXML (xml::Node* app) const throw ();
75 };
76
77 using namespace std;
78 using namespace anna::comm;
79
80 int main (int argc, const char** argv)
81 {
82    CommandLine& commandLine (CommandLine::instantiate ());
83    ArithmeticServer app;
84
85    srand (time (NULL));
86    
87    try {
88       commandLine.initialize (argv, argc);
89       commandLine.verify ();
90
91       Logger::setLevel (Logger::Debug); 
92       Logger::initialize ("arithmeticServer", new TraceWriter ("file.trace",4096000));
93  
94       app.start ();
95    }
96    catch (Exception& ex) {
97       cout << ex.asString () << endl;
98    }
99    
100    return 0;
101 }
102
103 ArithmeticServer::ArithmeticServer () : 
104    Application ("arithmeticServer", "Servidor de operaciones (iRS)", "1.0"),
105    a_communicator (NULL)
106 {
107    CommandLine& commandLine (CommandLine::instantiate ());
108    
109    commandLine.add ("as", CommandLine::Argument::Optional, "Direccion broadcast en el que servidor atiende peticiones.");
110    commandLine.add ("ps", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende las peticiones.");
111    commandLine.add ("ac", CommandLine::Argument::Optional, "Direccion broadcast en el que cliente atiende respuestas.");
112    commandLine.add ("pc", CommandLine::Argument::Mandatory, "Puerto al que enviar las respuestas");
113    commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)");
114 }
115
116 //-----------------------------------------------------------------------------------------
117 // Inicializa el servidor de sockets.
118 //-----------------------------------------------------------------------------------------
119 void ArithmeticServer::initialize () 
120    throw (RuntimeException)
121 {
122    CommandLine& cl (CommandLine::instantiate ());
123
124    const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("as")));
125    int port = cl.getIntegerValue ("ps");
126
127    a_communicator = new MyCommunicator ();
128
129    INetAddress localAddress (device, port);
130    a_input = new DatagramSocket (DatagramSocket::ReadOnly, localAddress);
131    a_input->setReceiverFactory (a_receiverFactory);
132    a_communicator->attach (a_input);
133
134    device = Network::instantiate ().find (Device::asAddress (cl.getValue ("ac")));
135    port = cl.getIntegerValue ("pc");
136
137    INetAddress remoteAddress (device, port);
138    a_output = new DatagramSocket (DatagramSocket::WriteOnly, remoteAddress);
139    a_output->connect ();
140 }
141
142 //-----------------------------------------------------------------------------------------
143 // Atiende las peticiones.
144 // Cuando hay un nuevo mensaje invocar�a Communicator::eventReceiveMessage
145 //-----------------------------------------------------------------------------------------
146 void ArithmeticServer::run ()
147    throw (RuntimeException)
148 {
149    CommandLine& cl (CommandLine::instantiate ());
150
151    if (cl.exists ("trace"))
152       Logger::setLevel (Logger::asLevel (cl.getValue ("trace")));
153
154    a_communicator->accept ();
155 }
156
157 xml::Node* ArithmeticServer::asXML (xml::Node* app) const 
158    throw ()
159 {
160    xml::Node* node = app::Application::asXML (app);
161    
162    node->createAttribute ("MaxMessage", a_communicator->getMaxMessage ());
163    node->createAttribute ("Message", a_communicator->getMessage ());
164    
165    return node;
166 }
167
168 void MyReceiver::initialize ()
169    throw (RuntimeException)
170 {
171    a_communicator = app::functions::component <MyCommunicator> (ANNA_FILE_LOCATION);
172 }
173
174 void MyReceiver::apply (ClientSocket&, const Message& message) 
175    throw (RuntimeException)
176 {
177    LOGMETHOD (TraceMethod tm ("MyReceiver", "apply", ANNA_FILE_LOCATION));
178
179    a_request.decode (message.getBody ());
180
181    a_communicator->delay ();
182
183    a_response.x = a_request.x;
184    a_response.y = a_request.y;
185    a_response.initTime = a_request.initTime;
186
187    switch (a_response.op = a_request.op) {
188       case '+':
189          a_response.result = a_request.x + a_request.y;
190          break;
191       case '-':
192          a_response.result = a_request.x - a_request.y;
193          break;
194       case '*':
195          a_response.result = a_request.x * a_request.y;
196          break;
197       case '/':
198          a_response.result = (a_request.y != 0) ? (a_request.x / a_request.y): 0;
199          break;
200    }
201
202    LOGINFORMATION (
203       string msg = anna::functions::asString ("%d %c %d = %d", a_request.x, a_request.op, a_request.y, a_response.result);
204       msg += anna::functions::asText (" | InitTime: ",  a_response.initTime);
205       Logger::information (msg, ANNA_FILE_LOCATION);
206    )
207
208    try {
209       static_cast <ArithmeticServer&> (app::functions::getApp ()).getOutput ()->send (a_response);
210    }
211    catch (Exception& ex) {
212       ex.trace ();
213    }
214 }