Remove dynamic exceptions
[anna.git] / example / http / rServer / 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 sera HTTP
11   ver http::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   Para poder probar el sistema de congestion se puede indicar un numero de milisegundos de
15   retardo aplicados a cada contestacion.
16   
17   Los clientes pueden ser: http_kclient.p http_client.p
18 */
19 #include <iostream>
20
21 #include <anna/core/core.hpp>
22
23 #include <anna/xml/Node.hpp>
24 #include <anna/xml/Attribute.hpp>
25
26 #include <anna/comm/comm.hpp>
27
28 #include <anna/http/Request.hpp>
29 #include <anna/http/Response.hpp>
30 #include <anna/http/Handler.hpp>
31 #include <anna/http/Transport.hpp>
32 #include <anna/http/functions.hpp>
33
34 #include <anna/test/Request.hpp>
35 #include <anna/test/Response.hpp>
36 #include <anna/test/Communicator.hpp>
37
38
39
40 using namespace std;
41
42 class MyCommunicator : public test::Communicator {
43 public:
44    MyCommunicator () {;}
45 };
46
47 class MyHandler : public http::Handler {
48 public:
49    MyHandler () : http::Handler ("http_rserver::MyHandler") {;}
50
51    static const char* className () { return "http_rserver::ReceiverFactory"; }
52
53 private:
54    MyCommunicator* a_communicator;
55    test::Request a_testRequest;
56    test::Response a_testResponse;
57
58    void initialize () noexcept(false);
59    void evRequest (ClientSocket&, const http::Request& request) noexcept(false);
60    void evResponse (ClientSocket&, const http::Response&) noexcept(false) {;}
61 };
62
63 class HTTPArithmeticServer : public comm::Application {
64 public:
65    HTTPArithmeticServer ();
66       
67 private:
68    MyCommunicator a_communicator;
69    ReceiverFactoryImpl <MyHandler> a_receiverFactory;
70    comm::ServerSocket* a_serverSocket;
71
72    void initialize () noexcept(false);
73    void run () noexcept(false);
74    xml::Node* asXML (xml::Node* app) const ;
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    HTTPArithmeticServer app;
84
85    http::functions::initialize ();
86
87    srand (time (NULL));
88
89    try {
90       commandLine.initialize (argv, argc);
91       commandLine.verify ();
92
93       Logger::setLevel (Logger::Debug); 
94       Logger::initialize ("http_server", new anna::TraceWriter ("file.trace", 4048000));
95  
96       app.start ();
97    }
98    catch (Exception& ex) {
99       cout << ex.asString () << endl;
100    }
101    
102    return 0;
103 }
104
105 HTTPArithmeticServer::HTTPArithmeticServer () : 
106    Application ("http_rserver", "Servidor HTTP de operaciones aritmeticas (iRS)", "1.0") 
107 {
108    CommandLine& commandLine (CommandLine::instantiate ());
109       
110    commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que atender peticiones");
111    commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP en la que atender");
112    commandLine.add ("d", CommandLine::Argument::Mandatory, "Retardo aplicado a la contestacion");
113    commandLine.add ("r", CommandLine::Argument::Optional, "Indicador de reuso de direccin", false);
114    commandLine.add ("limit", CommandLine::Argument::Mandatory, "% de ocupacion que permitimos");
115    commandLine.add ("n", CommandLine::Argument::Optional, "Numero de mensajes a servir", true);
116    commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)");
117    commandLine.add ("timeout", CommandLine::Argument::Optional, "Timeout (ms) del cliente sin enviar peticiones");
118    commandLine.add ("quota", CommandLine::Argument::Optional, "Numero de bytes aceptados antes de cerrar el socket");
119 }
120
121 void HTTPArithmeticServer::initialize () 
122    noexcept(false)
123 {
124    CommandLine& cl (CommandLine::instantiate ());
125
126    int port = cl.getIntegerValue ("p");
127    const comm::Device* device = Network::instantiate ().find (Device::asAddress (cl.getValue ("a")));
128
129    comm::TransportFactory* ttff = &http::Transport::getFactory ();
130
131    if (cl.exists ("quota") == true) 
132       ttff->setOverQuotaSize (cl.getIntegerValue ("quota"));
133
134    a_serverSocket = new ServerSocket (INetAddress (device, port), cl.exists ("r"), ttff);
135    a_serverSocket->setReceiverFactory (a_receiverFactory);
136 }
137
138 void HTTPArithmeticServer::run ()
139    noexcept(false)
140 {
141    CommandLine& cl (CommandLine::instantiate ());
142
143    a_communicator.attach (a_serverSocket);
144    a_communicator.setDelay ((Millisecond)cl.getIntegerValue ("d"));
145
146    if (cl.exists ("n") == true)
147       a_communicator.setMaxMessage (cl.getIntegerValue ("n"));
148
149    if (cl.exists ("trace"))
150       Logger::setLevel (Logger::asLevel (cl.getValue ("trace")));
151
152    CongestionController::instantiate ().setLimit (cl.getIntegerValue ("limit"));
153
154    if (cl.exists ("timeout") == true)
155       a_communicator.setTimeout ((Millisecond)cl.getIntegerValue ("timeout"));
156
157    a_communicator.accept ();
158 }
159
160 xml::Node* HTTPArithmeticServer::asXML (xml::Node* app) const 
161    
162 {
163    xml::Node* node = app::Application::asXML (app);
164    
165    node->createAttribute ("MaxMessage", a_communicator.getMaxMessage ());
166    node->createAttribute ("Message", a_communicator.getMessage ());
167    
168    return node;
169 }
170
171 void MyHandler::initialize ()
172    noexcept(false)
173 {
174    a_communicator = app::functions::component <MyCommunicator> (ANNA_FILE_LOCATION);
175    allocateResponse ()->createHeader (http::Header::Type::Date); 
176 }
177
178 void MyHandler::evRequest (ClientSocket& clientSocket, const http::Request& request)
179    noexcept(false)
180 {
181    LOGMETHOD (TraceMethod tm ("MyReceiver", "apply", ANNA_FILE_LOCATION));
182
183    if (a_communicator->canContinue (clientSocket) == false)
184       return;      
185       
186    const DataBlock& body = request.getBody ();
187
188    if (body.getSize () == 0)
189       throw RuntimeException ("La peticion no incorpora los parametros de operacion", ANNA_FILE_LOCATION);
190
191    LOGINFORMATION (
192       string msg ("Body recibido: ");
193       msg += anna::functions::asString (body);
194       Logger::information (msg, ANNA_FILE_LOCATION);
195    );
196
197    if (Codec::getType (body) != test::Request::Id) 
198       throw RuntimeException ("El mensaje recibido no es una peticion aritmetica", ANNA_FILE_LOCATION);
199
200    a_testRequest.decode (body);
201    
202    a_communicator->delay ();
203
204    a_testResponse.x = a_testRequest.x;
205    a_testResponse.y = a_testRequest.y;
206    a_testResponse.initTime = a_testRequest.initTime;
207    
208    http::Response* response = allocateResponse ();
209
210    response->setStatusCode (200);
211
212    switch (a_testResponse.op = a_testRequest.op) {
213       case '+':
214          a_testResponse.result = a_testRequest.x + a_testRequest.y;
215          break;
216       case '-':
217          a_testResponse.result = a_testRequest.x - a_testRequest.y;
218          break;
219       case '*':
220          a_testResponse.result = a_testRequest.x * a_testRequest.y;
221          break;
222       case '/':
223          if (a_testRequest.y == 0) {
224             response->setStatusCode (400);
225             response->setReasonPhrase ("Division por cero");
226             a_testResponse.result = 0;
227          }
228          else
229             a_testResponse.result = a_testRequest.x / a_testRequest.y;
230          break;
231    }
232
233    response->setBody (a_testResponse.code ());      
234
235    response->find (http::Header::Type::Date)->setValue ("Mon, 30 Jan 2006 14:36:18 GMT");
236    
237    http::Header* keepAlive = response->find ("Keep-Alive");
238    
239    if (keepAlive == NULL)
240       keepAlive = response->createHeader ("Keep-Alive");   
241    
242    keepAlive->setValue ("Verificacion del cambio 1.0.7");      
243
244    LOGINFORMATION (
245       string msg = anna::functions::asString ("%d %c %d = %d", a_testRequest.x, a_testRequest.op, a_testRequest.y, a_testResponse.result);
246       Logger::information (msg, ANNA_FILE_LOCATION);
247    );
248
249    try {
250       clientSocket.send (*response);
251    }
252    catch (Exception& ex) {
253       ex.trace ();
254    }
255 }
256