NATIVES_SRC: java_messages.h

File java_messages.h, 6.0 KB (added by boyanl, 15 years ago)
Line 
1/*
2 * Message.h
3 *
4 *  Created on: Aug 18, 2009
5 *      Author: nenko
6 */
7
8#ifndef MESSAGE_H_
9#define MESSAGE_H_
10
11#ifdef __WIN32__
12       #define WINDOWS
13#endif
14
15#ifdef __WIN64__
16       #define WINDOWS
17#endif
18
19#ifdef WINDOWS
20       #include <io.h>
21       #include <fcntl.h>
22#endif
23
24#include <cstring>
25#include "util.h"
26
27enum CommandIds {
28        STOP_COMMAND_ID = 0, START_COMMAND_ID
29};
30
31enum ResponseIds {
32        OK_RESPONSE_ID = 0, ERROR_RESPONSE_ID
33};
34
35class Message {
36protected:
37        int id;
38public:
39        vector<byte> const data;
40
41        Message(vector<byte> const& _data, int& pos) :
42                data(_data) {
43                //the position should be in the beginning before reading
44                assert(pos == 0);
45                id = readInt(data, pos);
46        }
47
48        Message(vector<byte> const& _data) :
49                data(_data) {
50                int pos = 0;
51                id = readInt(data, pos);
52        }
53
54        virtual ~Message() {
55        }
56
57        int getId() {
58                return id;
59        }
60
61        static int readInt(vector<byte> const& data, int& pos) {
62                int res = 0;
63                res |= data[pos++] << 0;
64                res |= data[pos++] << 8;
65                res |= data[pos++] << 16;
66                res |= data[pos++] << 24;
67                return res;
68        }
69
70        /*
71         * Passing the 3rd argument (result) by reference to avoid returning the vector and copying
72         * res must be empty
73         */
74        static void readBinData(vector<byte> const& data, int& pos, vector<byte>& res) {
75                int len = readInt(data, pos);
76                res.resize (len);
77                memcpy (&res[0], &data[pos], len);
78                pos += len;
79        }
80
81        //TODO currently will work only for ascii
82        static string readStringUtf8(vector<byte> const& data, int& pos) {
83                string res = "";
84                int len = readInt(data, pos);
85                for (int i = 0; i < len; ++i) {
86                        res += char(data.at(pos++));
87                }
88                return res;
89        }
90
91        static void writeInt(vector<byte>& data, int value) {
92                data.push_back(byte(value >> 0));
93                data.push_back(byte(value >> 8));
94                data.push_back(byte(value >> 16));
95                data.push_back(byte(value >> 24));
96                //fprintf(stderr, "int to be put: %d; bytes putted: %d %d %d %d\n", value, value >> 0, value >> 8, value >> 16, value >> 24);
97//                              data.at(0), data.at(1), data.at(2), data.at(3));
98        }
99
100        //the third argument is added, because otherwise this was not consistent with readBinData
101        static void writeBinData(vector<byte>& data, const vector<byte>& source, bool withSize = true) {
102                if(withSize) {
103                        writeInt(data, (int)source.size());
104                }
105                int sz = data.size ();
106                data.resize (sz + source.size());
107                memcpy (&data[sz], &source[0], source.size());
108        }
109
110        static void writeStringUtf8(vector<byte>& data, string const& value) {
111                writeInt(data, value.size());
112                for (int i = 0; i < (int) value.size(); ++i) {
113                        data.push_back(value[i]);
114                }
115        }
116
117};
118
119// response do not need polymorphism
120class Response: public Message {
121public:
122        Response(vector<byte> const& _data) :
123                Message(_data) {
124        }
125
126        static Response createOk() {
127                vector<byte> data;
128                writeInt(data, OK_RESPONSE_ID);
129                return Response(data);
130        }
131
132        static Response createError(string const& message) {
133                vector<byte> data;
134                writeInt(data, ERROR_RESPONSE_ID);
135                writeStringUtf8(data, message);
136                return Response(data);
137        }
138};
139
140// with polymorphism
141class Command: public Message {
142protected:
143        Command(vector<byte> const& _data, int& pos) :
144                Message(_data, pos) {
145        }
146public:
147        virtual Response execute() = 0;
148};
149
150//TODO: this start and stop are not very useful
151class StartCommand: public Command {
152public:
153        StartCommand(vector<byte> const& _data, int& pos) :
154                Command(_data, pos) {
155                assert(getId() == START_COMMAND_ID);
156                assert(pos == (int)_data.size());
157        }
158
159        virtual Response execute();
160};
161
162//StartCommand and StopCommand should be handled by polymorphism
163
164class StopCommand: public Command {
165public:
166        StopCommand(vector<byte> const& _data, int& pos) :
167                Command(_data, pos) {
168                assert(getId() == STOP_COMMAND_ID);
169        }
170
171        virtual Response execute();
172};
173
174class JavaBridge {
175        static JavaBridge* instance;
176public:
177        JavaBridge() {
178                assert(instance == NULL);
179                instance = this;
180        }
181        virtual ~JavaBridge() {
182                instance = NULL;
183        }
184
185        virtual Command* createCommand(int id, vector<byte> const& data, int& pos) {
186                switch (id) {
187                case START_COMMAND_ID:
188                        return new StartCommand(data, pos);
189                case STOP_COMMAND_ID:
190                        return new StopCommand(data, pos);
191                default:
192                        cerr << "bad id: " << id << endl;
193                        throw runtime_error("Unknown command id!");
194                }
195        }
196
197        void sendResponse(Response const& response) {
198                int size = response.data.size();
199                fwrite(&size, sizeof(int), 1, stdout);
200                fwrite(&response.data[0], 1, response.data.size(), stdout);
201                fflush(stdout);
202        }
203
204        //the caller is responsible to delete the returned command!
205        Command* readCommand() {
206                //fprintf(stderr, "readCommand(): begin reading command\n"); fflush(stderr);
207                int size;
208//              cin.read((char*) &size, sizeof(int));
209        int rc = fread(&size, sizeof(int), 1, stdin);
210        assert(rc == 1);
211                //fprintf(stderr, "readCommand(): size = %d\n", size); fflush(stderr);
212                vector<byte> data(size);
213
214                rc = fread(&data[0], 1, size, stdin);
215                int pos = 0;
216                int id = Message::readInt(data, pos);
217                pos = 0; //reset pos           
218                //fprintf(stderr, "readCommand(): end reading command\n"); fflush(stderr);
219                return createCommand(id, data, pos);
220        }
221
222        void mainLoop() {
223//              cerr << "mainLoop()" << endl;
224
225#ifdef WINDOWS
226        _setmode( _fileno( stdin ), _O_BINARY );
227            _setmode( _fileno( stdout ), _O_BINARY );
228#endif
229
230                while (true) {
231                        //BEGIN_TIME;
232                        Command *cmd = readCommand();
233                        //                      cerr << "received command_id: " << cmd->getId() << "; executing..."     << endl;
234                        assert(cmd != NULL);
235
236                        try {
237                                Response res = cmd->execute();
238                                //                      cerr << "sending response: " << res.getId() << " for command id: "      << cmd->getId() << endl;
239                                sendResponse(res);
240                                if (cmd->getId() == STOP_COMMAND_ID) {
241                                        // Temporary solution until we figure out how to kill threads
242                                        exit(0);
243                                        break;
244                                }
245                        }
246                        catch(runtime_error const& ex) {
247                                sendResponse(Response::createError(ex.what()));
248                        }
249                        //END_TIME("JavaMessages::mainLoop() loop");
250                        delete cmd;
251                }
252
253        }
254
255        static JavaBridge& getInstance() {
256                return *instance;
257        }
258
259        virtual Response doStart() {
260                return Response::createOk();
261        }
262
263        virtual Response doStop() {
264                return Response::createOk();
265        }
266};
267
268#endif /* MESSAGE_H_ */