Updated license
[anna.git] / example / http / kClient / main.cpp
1 // ANNA - Anna is Not Nothingness Anymore
2 //
3 // (c) Copyright 2005-2014 Eduardo Ramos Testillano & Francisco Ruiz Rayo
4 //
5 // https://bitbucket.org/testillano/anna
6 //
7 // Redistribution and use in source and binary forms, with or without
8 // modification, are permitted provided that the following conditions
9 // are met:
10 //
11 //     * Redistributions of source code must retain the above copyright
12 // notice, this list of conditions and the following disclaimer.
13 //     * Redistributions in binary form must reproduce the above
14 // copyright notice, this list of conditions and the following disclaimer
15 // in the documentation and/or other materials provided with the
16 // distribution.
17 //     * Neither the name of Google Inc. nor the names of its
18 // contributors may be used to endorse or promote products derived from
19 // this software without specific prior written permission.
20 //
21 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
22 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
23 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
24 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
25 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
26 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
27 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
28 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
29 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
30 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
31 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
32 //
33 // Authors: eduardo.ramos.testillano@gmail.com
34 //          cisco.tierra@gmail.com
35
36
37 /*
38    Establece un manejador externo para controlar el teclado, recoge los parametros de la operacion
39    por este y envia la peticion al servidor que devolvera el resultado de aplicar la operacion
40    sobre los parametros recogidos.
41
42    El cliente de esta aplicacion es: http_server.p => Transporte: http::Transport.
43 */
44 #include <iostream>
45
46 #include <string.h>
47
48 #include <anna/core/core.hpp>
49 #include <anna/comm/comm.hpp>
50
51 #include <anna/http/Request.hpp>
52 #include <anna/http/Response.hpp>
53 #include <anna/http/Handler.hpp>
54 #include <anna/http/Transport.hpp>
55 #include <anna/http/functions.hpp>
56
57 #include <anna/test/Menu.hpp>
58 #include <anna/test/Request.hpp>
59 #include <anna/test/Response.hpp>
60
61 class MyHandler : public http::Handler {
62 public:
63    MyHandler () : http::Handler ("http_kclient::MyHandler") {;}
64
65 private:
66    http::Response a_httpResponse;
67    test::Response a_testResponse;
68
69    void evRequest (ClientSocket&, const http::Request&) throw (RuntimeException) {;}
70    void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException);
71 };
72
73 class MyCommunicator : public Communicator {
74 public:
75    MyCommunicator () : Communicator ()
76    {
77       a_httpRequest.setMethod (http::Method::Type::Post);
78       a_httpRequest.setURI ("HTTPKClient");
79    }
80
81 private:
82    MyHandler a_httpHandler;
83    http::Request a_httpRequest;
84    test::Request a_testRequest;
85
86    void eventReceiveMessage (ClientSocket &, const Message&) throw (RuntimeException);
87    void eventUser (const char* id, const void* context) throw ();
88 };
89
90 class HTTPKClient : public anna::comm::Application {
91 public:
92    HTTPKClient ();
93
94    Server* getServer () const throw () { return a_server; }
95    const test::Menu& getMenu () const throw () { return a_menu; }
96
97 private:
98    MyCommunicator a_communicator;
99    test::Menu a_menu;
100    Server* a_server;
101
102    void initialize () throw (RuntimeException);
103    void run () throw (RuntimeException);
104 };
105
106 using namespace std;
107 using namespace test;
108
109 int main (int argc, const char** argv)
110 {
111    CommandLine& commandLine (CommandLine::instantiate ());
112    HTTPKClient app;
113
114    http::functions::initialize ();
115
116    try {
117       commandLine.initialize (argv, argc);
118       commandLine.verify ();
119
120       Logger::setLevel (Logger::Debug);
121       Logger::initialize ("http_kclient", new TraceWriter ("file.trace", 4096000));
122
123       app.start ();
124    }
125    catch (Exception& ex) {
126       cout << ex.asString () << endl;
127    }
128
129    return 0;
130 }
131
132 HTTPKClient::HTTPKClient () :
133    Application ("kclient", "HTTPKClient", "1.0.0"),
134    a_menu (&a_communicator)
135 {
136    CommandLine& commandLine (CommandLine::instantiate ());
137
138    commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas.");
139    commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP Puerto en el que el servidor atiende respuestas.");
140 }
141
142 void HTTPKClient::initialize () 
143    throw (RuntimeException)
144 {
145    CommandLine& cl (CommandLine::instantiate ());
146
147    Network& network = Network::instantiate ();
148
149    Host* host = network.find_host ("host000");
150    host->assign (network.find (Device::asAddress (cl.getValue ("a"))));
151    a_server = host->createServer ("http_server", cl.getIntegerValue ("p"), true, &http::Transport::getFactory ());
152
153    a_communicator.attach (&a_menu);
154 }
155
156 void HTTPKClient::run ()
157    throw (RuntimeException)
158 {
159    a_menu.paint ();
160    a_communicator.accept ();
161 }
162
163 void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const Message& message)
164    throw (RuntimeException)
165 {
166    LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION));
167
168    if (clientSocket.support (http::Transport::className ()) == false)
169       return;
170
171    a_httpHandler.apply (clientSocket, message);
172 }
173
174 //-----------------------------------------------------------------------------------------
175 // Cuando el Menu tiene disponibles todos los datos necesarios para la peticin se lo
176 // notifica al comunicador mediante un evento de usuario.
177 //-----------------------------------------------------------------------------------------
178 void MyCommunicator::eventUser (const char* id, const void* context)
179    throw ()
180 {
181    LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventUser", ANNA_FILE_LOCATION));
182
183    if (anna_strcmp (id, Menu::EventData) == 0) {
184       const Menu::Data* data (reinterpret_cast <const Menu::Data*>  (context));
185
186       a_testRequest.op = data->a_operation;
187       a_testRequest.x = data->a_op1;
188       a_testRequest.y = data->a_op2;
189       a_testRequest.initTime = anna::functions::millisecond ();
190
191       Server* server = static_cast <HTTPKClient&> (anna::comm::functions::getApp ()).getServer ();
192
193       try {
194          a_httpRequest.setBody (a_testRequest.code ());
195          server->send (a_httpRequest);
196       }
197       catch (RuntimeException& ex) {
198          ex.trace ();
199       }
200    } 
201 }
202
203 void MyHandler::evResponse (ClientSocket& clientSocket, const http::Response& response)
204    throw (RuntimeException)
205 {
206    if (response.getStatusCode () == 200) {
207       a_testResponse.decode (response.getBody ());
208       
209       const Millisecond responseTime = anna::functions::millisecond () - a_testResponse.initTime;  
210       cout << endl << "ResponseTime: " << responseTime << " ms" << endl;
211       cout << endl << "Resultado de la peticion: " << a_testResponse.x << (char) a_testResponse.op << a_testResponse.y  << " = " << a_testResponse.result << endl << endl;
212    }
213    else 
214       cout << endl << "Error en la peticion: " << response.getStatusCode () << " (" << response.getReasonPhrase () << ")" << endl << endl;
215    
216    static_cast <HTTPKClient&> (anna::comm::functions::getApp ()).getMenu ().paint ();
217 }
218