[libamb] - added value quality, removed deprecated GetFoo call, made updateFrequency...
[profile/ivi/automotive-message-broker.git] / plugins / common / jsonprotocol.h
1 /*
2 Copyright (C) 2015 Intel Corporation
3
4 This library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 This library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with this library; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17 */
18
19 #ifndef AMB_JSON_PROTOCOL_H_
20 #define AMB_JSON_PROTOCOL_H_
21
22 #include <functional>
23 #include <memory>
24 #include <string>
25 #include <unordered_map>
26 #include <vector>
27
28 #include <abstractroutingengine.h>
29 #include <mappropertytype.hpp>
30 #include <picojson.h>
31 #include <uuidhelper.h>
32 #include <vehicleproperty.h>
33
34 #include "abstractio.hpp"
35
36
37 namespace amb
38 {
39
40 template <class T>
41 class PtrMaker
42 {
43 public:
44         typedef std::shared_ptr<T> Ptr;
45
46         static std::shared_ptr<T> create()
47         {
48                 return Ptr(new T());
49         }
50 };
51
52 class Object : public std::unordered_map<std::string, std::shared_ptr<AbstractPropertyType>>, public PtrMaker<Object>
53 {
54 public:
55         Object(): std::unordered_map<std::string, std::shared_ptr<AbstractPropertyType>>() { }
56         Object(const std::string & ifaceName): std::unordered_map<std::string, std::shared_ptr<AbstractPropertyType>>(),
57                 interfaceName(ifaceName)
58         {
59
60         }
61
62         static Object::Ptr fromJson(const picojson::object & obj);
63
64         static picojson::value toJson(const Object::Ptr & obj);
65
66         std::string interfaceName;
67 };
68
69
70 class BaseMessage
71 {
72 public:
73         BaseMessage():BaseMessage("", "message") { }
74
75         BaseMessage(std::string t): BaseMessage("", t) {}
76
77         BaseMessage(std::string n, std::string t)
78                 : name(n), type(t)
79         {
80                 messageId = amb::createUuid();
81         }
82
83         BaseMessage(const BaseMessage & other)
84                 : BaseMessage(other.name, other.type)
85         {
86
87         }
88
89         std::string name;
90         std::string type;
91
92         std::string messageId;
93
94         virtual picojson::value toJson();
95         virtual bool fromJson(const picojson::value & json);
96
97         template <typename T>
98         bool is()
99         {
100                 return T::is(this);
101         }
102
103         static bool validate(const picojson::value & json)
104         {
105                 return json.is<picojson::object>() && json.contains("type") && json.contains("name") && json.contains("messageId");
106         }
107
108         template <typename T>
109         static bool is(const picojson::value & json)
110         {
111                 return T::is(json);
112         }
113
114 protected:
115
116         picojson::value data;
117
118 private:
119 };
120
121 class MethodCall : public BaseMessage
122 {
123 public:
124         MethodCall(std::string name)
125                 :BaseMessage(name, "method"), zone(Zone::None)
126         {
127
128         }
129
130         MethodCall(const BaseMessage & other)
131                 :BaseMessage(other), zone(Zone::None)
132         {
133                 name = other.name;
134         }
135
136         MethodCall(const MethodCall & other)
137                 :MethodCall(other.name)
138         {
139                 sourceUuid = other.sourceUuid;
140                 zone = other.zone;
141         }
142
143         static bool is(const BaseMessage * msg)
144         {
145                 return (msg->type == "method");
146         }
147
148         /*!
149          * \brief is checks if json message is of this message type
150          * Assumes that json is already a valid \ref BaseMessage
151          * \param json
152          * \return
153          */
154         static bool is(const picojson::value & json)
155         {
156                 return json.contains("source") && json.get("source").is<std::string>()
157                                 && json.contains("zone") && json.get("zone").is<double>();
158         }
159
160         virtual picojson::value toJson();
161         virtual bool fromJson(const picojson::value &json);
162
163         std::string sourceUuid;
164         Zone::Type zone;
165 };
166
167 template <class T>
168 class MethodReply
169 {
170 public:
171
172         MethodReply(): MethodReply(nullptr, false) {}
173         MethodReply(std::shared_ptr<T> t, bool success): mMethod(t), methodSuccess(success), err(AsyncPropertyReply::NoError) { }
174         bool methodSuccess;
175
176         picojson::value toJson()
177         {
178                 picojson::value v = mMethod->toJson();
179
180                 picojson::object obj = v.get<picojson::object>();
181                 obj["methodSuccess"] = picojson::value(methodSuccess);
182                 obj["error"] = picojson::value((double)err);
183
184                 return picojson::value(obj);
185         }
186
187         bool fromJson(const picojson::value & json)
188         {
189                 if(!mMethod) mMethod = std::shared_ptr<T>(new T());
190                 mMethod->fromJson(json);
191                 methodSuccess = json.get("methodSuccess").get<bool>();
192                 err = AsyncPropertyReply::Error(json.get("error").get<double>());
193
194                 return true;
195         }
196
197         static bool is(const picojson::value & v)
198         {
199                 return v.contains("methodSuccess") && v.contains("error") && v.get("methodSuccess").is<bool>()
200                                 && v.get("error").is<double>() && T::is(v);
201         }
202
203         AsyncPropertyReply::Error error()
204         {
205                 return err;
206         }
207
208         const std::string errorString() { return AsyncPropertyReply::errorToStr(err); }
209
210         const std::shared_ptr<T> method() { return mMethod; }
211
212 protected:
213         std::shared_ptr<T> mMethod;
214         AsyncPropertyReply::Error err;
215 };
216
217 typedef std::function<void (std::vector<Object::Ptr>)> ListCallback;
218
219 class ListMethodCall : public MethodCall, public PtrMaker<ListMethodCall>
220 {
221 public:
222         ListMethodCall(): MethodCall("list") {}
223         ListMethodCall(const MethodCall & other)
224                 :MethodCall(other)
225         {
226                 if(!is(&other))
227                         throw std::runtime_error("type not list");
228         }
229
230         picojson::value toJson();
231         bool fromJson(const picojson::value &json);
232
233         std::vector<Object::Ptr> objectNames;
234
235         ListCallback replyCallback;
236
237         static bool is(const BaseMessage * msg)
238         {
239                 return msg->name == "list";
240         }
241
242         static bool is(const picojson::value & json)
243         {
244                 return json.get("name").to_str() == "list";
245         }
246 };
247
248 typedef std::function<void (Object::Ptr)> ObjectCallback;
249
250 class GetMethodCall : public MethodCall, public PtrMaker<GetMethodCall>
251 {
252 public:
253         GetMethodCall()
254                 : MethodCall("get")
255         {
256
257         }
258
259         picojson::value toJson();
260         bool fromJson(const picojson::value &json);
261
262         static bool is(const BaseMessage * msg)
263         {
264                 return msg->name == "get";
265         }
266
267         static bool is(const picojson::value & json)
268         {
269                 return json.get("name").to_str() == "get";
270         }
271
272         Object::Ptr value;
273
274         ObjectCallback replyCallback;
275 };
276
277 typedef std::function<void (bool)> SetCallback;
278
279 class SetMethodCall : public MethodCall, public PtrMaker<SetMethodCall>
280 {
281 public:
282         SetMethodCall()
283                 : MethodCall("set")
284         {
285
286         }
287
288         picojson::value toJson();
289         bool fromJson(const picojson::value &json);
290
291         static bool is(const BaseMessage * msg)
292         {
293                 return msg->name == "set";
294         }
295
296         static bool is(const picojson::value & json)
297         {
298                 return json.get("name").to_str() == "set";
299         }
300
301         Object::Ptr value;
302         SetCallback replyCallback;
303 };
304
305 class SubscribeMethodCall : virtual public MethodCall, public PtrMaker<SubscribeMethodCall>
306 {
307 public:
308         SubscribeMethodCall()
309                 :SubscribeMethodCall("")
310         {
311
312         }
313         SubscribeMethodCall(const std::string & ifaceName)
314                 :MethodCall("subscribe"), interfaceName(ifaceName)
315         {
316
317         }
318
319         picojson::value toJson();
320         bool fromJson(const picojson::value &json);
321
322         static bool is(const BaseMessage *msg)
323         {
324                 return msg->name == "subscribe";
325         }
326
327         static bool is(const picojson::value & json)
328         {
329                 return json.get("name").to_str() == "subscribe";
330         }
331
332         std::string interfaceName;
333 };
334
335 class UnsubscribeMethodCall : public MethodCall, public PtrMaker<UnsubscribeMethodCall>
336 {
337 public:
338         UnsubscribeMethodCall()
339                 :UnsubscribeMethodCall("")
340         {
341
342         }
343
344         UnsubscribeMethodCall(const SubscribeMethodCall & call)
345                 : UnsubscribeMethodCall(call.interfaceName)
346         {
347                 sourceUuid = call.sourceUuid;
348                 zone = call.zone;
349         }
350
351         UnsubscribeMethodCall(const std::string & ifaceName)
352                 :MethodCall("unsubscribe"), interfaceName(ifaceName)
353         {
354
355         }
356
357         static bool is(const BaseMessage *msg)
358         {
359                 return msg->name == "unsubscribe";
360         }
361
362         static bool is(const picojson::value & json)
363         {
364                 return json.get("name").to_str() == "unsubscribe";
365         }
366
367         picojson::value toJson();
368         bool fromJson(const picojson::value &json);
369
370         std::string interfaceName;
371 };
372
373 class EventMessage : public BaseMessage
374 {
375 public:
376         EventMessage(const std::string & name)
377                 :BaseMessage("event", name) {}
378
379         static bool is(const BaseMessage & msg)
380         {
381                 return msg.type == "event";
382         }
383
384         static bool is(const picojson::value &json)
385         {
386                 return json.get("type").to_str() == "event";
387         }
388 };
389
390 class TimeSyncMessage : public BaseMessage, public PtrMaker<TimeSyncMessage>
391 {
392 public:
393         TimeSyncMessage()
394                 :BaseMessage("timeSync", "message"), serverTime(0)
395         {
396
397         }
398
399         double serverTime;
400
401         picojson::value toJson();
402         bool fromJson(const picojson::value &json);
403
404         static bool is(const BaseMessage & msg)
405         {
406                 return msg.type == "message" && msg.name == "timeSync";
407         }
408
409         static bool is(const picojson::value &json)
410         {
411                 return json.contains("serverTime") && json.get("name").to_str() == "timeSync" && json.get("serverTime").is<double>();
412         }
413 };
414
415 class PropertyChangeEvent: public EventMessage, public PtrMaker<PropertyChangeEvent>
416 {
417 public:
418         PropertyChangeEvent() : EventMessage("propertyChanged"), zone(Zone::None) {}
419
420
421         picojson::value toJson();
422         bool fromJson(const picojson::value &json);
423
424         static bool is(const BaseMessage & msg)
425         {
426                 return msg.type == "event" && msg.name == "propertyChanged";
427         }
428
429         static bool is(const picojson::value &json)
430         {
431                 return EventMessage::is(json) && json.get("name").to_str() == "propertyChanged" && json.contains("data") && json.get("data").is<picojson::object>();
432         }
433
434         Object::Ptr value;
435         std::string sourceUuid;
436         Zone::Type zone;
437 };
438
439 class BaseJsonMessageReader
440 {
441 public:
442         BaseJsonMessageReader(AbstractIo* io);
443
444         void canHasData();
445         void closed();
446
447         std::function<void (void)> disconnected;
448
449 protected:
450
451         virtual void hasJsonMessage(const picojson::value & message) = 0;
452
453         template <class T>
454         void send(T & msg)
455         {
456                 std::string buff = msg.toJson().serialize()+"\n";
457                 DebugOut() << "writing: " << buff << endl;
458                 mIo->write(buff);
459         }
460
461         template <class T>
462         void send(std::shared_ptr<T> msg)
463         {
464                 std::string buff = msg->toJson().serialize()+"\n";
465                 DebugOut() << "writing: " << buff << endl;
466                 mIo->write(buff);
467         }
468
469         std::shared_ptr<AbstractIo> mIo;
470
471 private:
472
473         bool hasJson();
474
475         std::string incompleteMessage;
476
477 };
478
479 class AmbRemoteClient: public BaseJsonMessageReader
480 {
481 public:
482
483         class Subscription
484         {
485         public:
486                 Subscription(SubscribeMethodCall subscribeCall, const ObjectCallback & cb)
487                         :call(subscribeCall), callback(cb) {}
488                 bool operator ==(const Subscription &rhs)
489                 {
490                         return rhs.subscriptionId() == subscriptionId();
491                 }
492
493                 const std::string subscriptionId() const { return call.messageId; }
494                 SubscribeMethodCall call;
495                 ObjectCallback callback;
496         };
497
498         AmbRemoteClient(AbstractIo* io);
499
500         void list(ListCallback cb);
501
502         void get(const std::string & objectName, ObjectCallback cb);
503
504         void get(const std::string & objectName, const std::string & sourceUuid, ObjectCallback cb);
505
506         void get(const std::string & objectName, Zone::Type zone, ObjectCallback cb);
507
508         void get(const std::string & objectName, const std::string & sourceUuid, Zone::Type zone, ObjectCallback cb);
509
510         void set(const std::string & objectName,  Object::Ptr value, SetCallback cb);
511
512         void set(const std::string & objectName, Object::Ptr value, const std::string & sourceUuid, Zone::Type zone, SetCallback cb);
513
514         const std::string subscribe(const std::string & objectName, const std::string & sourceUuid, Zone::Type zone, ObjectCallback cb);
515
516         void subscribe(const std::string & objectName, ObjectCallback cb);
517
518         void unsubscribe(const std::string & subscribeId);
519
520 protected:
521
522         double correctTimeFromServer(double serverTimestamp);
523
524 private:
525
526         void hasJsonMessage(const picojson::value & message);
527
528         std::string createSubscriptionId(const std::string & objectName,  const std::string & sourceUuid, Zone::Type zone);
529         std::vector<ListMethodCall::Ptr> mListCalls;
530         std::vector<GetMethodCall::Ptr> mGetMethodCalls;
531         std::vector<SetMethodCall::Ptr> mSetMethodCalls;
532         std::unordered_map<std::string, std::vector<Subscription>> mSubscriptions;
533
534         double serverTimeOffset;
535 };
536
537 class AmbRemoteServer : public BaseJsonMessageReader, public PtrMaker<AmbRemoteServer>
538 {
539 public:
540         AmbRemoteServer(AbstractIo* io, AbstractRoutingEngine* routingEngine);
541
542 protected:
543
544         /*!
545          * \brief list called when a ListMessageCall was received
546          */
547         virtual void list(ListMethodCall::Ptr call);
548
549         /*!
550          * \brief get called when a GetMessageCall was received
551          */
552         virtual void get(GetMethodCall::Ptr get);
553
554         /*!
555          * \brief set called when SetMessageCall was received
556          */
557         virtual void set(SetMethodCall::Ptr set);
558         /*!
559          * \brief listen called when ListenMessageCall was received
560          */
561         virtual void subscribe(SubscribeMethodCall::Ptr call);
562
563         virtual void unsubscribe(UnsubscribeMethodCall::Ptr call);
564
565         void hasJsonMessage(const picojson::value & json);
566
567 protected:
568         AbstractRoutingEngine* routingEngine;
569 };
570
571 } //namespace amb
572
573 #endif