Initial merge-commit of the OIC code. Should successfully do discovery for single...
[platform/upstream/iotivity.git] / examples / test_OCReflect.cpp
1 //******************************************************************
2 //
3 // Copyright 2014 Intel Corporation All Rights Reserved.
4 //-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
5
6
7 #include <iostream>
8 #include <functional>
9
10 #include "OCServer.h"
11 #include "OCReflect.h"
12 #include "OCException.h"
13 #include "OCProperties.h"
14
15 namespace OC { namespace OCReflect {
16
17 // JFW:
18 /*
19 template <class BoundF>
20 struct call_through
21 {
22  BoundF& f;
23
24  const property_type            return_type;
25  const property_type_vector     param_types;
26
27  call_through(BoundF& f_, const property_type& return_type_, const property_type_vector param_types_)
28   : f(f_), return_type(return_type_), param_types(param_types_)
29  {}
30
31  property operator()()
32  {
33         return make_property(f(), "return value"); // JFW: need a version of this for anonymous properties
34  }
35
36  template <class ...XS>
37  property operator()(const XS& ...params)
38  {
39         // switch(p0_type)
40         //return make_property(f(), "foo");
41
42         f(params...);
43
44 //      return make_property(f(params...), "fancy result name");
45
46         return make_property("Hello, World!", "fancy result name");
47  }
48 };
49 */
50
51 template <typename InstanceT, typename MethodT>
52 OC::OCReflect::bound_function bind_function(InstanceT *self, MethodT const& method)
53 {
54  return [self, method](const property_vector& args) -> property
55         {
56             auto b = std::bind(method, self); 
57             return OC::OCReflect::make_property::apply(b(args), "_ret_"); 
58         };
59 }
60
61 template <typename InstanceT, typename MethodT, typename ...ParameterT>
62 void bind_service(OC::OCServer& server, InstanceT *self, MethodT const& method, const std::string& binding_name, const property_type& return_type, const ParameterT& ...param_types)
63 {
64  OC::OCReflect::bound_function f { 
65     [method, self](const property_vector& args) -> property 
66     { 
67         // JFW: auto b = std::bind(method, self); 
68
69 /* JFW: eventually, map parameters in to e return OC::OCReflect::make_property::apply(b(args), "_ret_"); 
70         ...this is tricky, so we' punting on it for the Tuesday release. */
71
72         return OC::OCReflect::make_property::apply("hello from your friendly neighborhood lambda", "return value");
73     }
74  };
75
76  OC::OCReflect::method_binding fmb(binding_name, f,
77                                    return_type, property_type_vector { param_types... });
78
79  server.bind(fmb);
80  
81 /*
82  call_through<decltype(b)> ct(b, return_type, ptypes);
83
84  // then, at the call site...
85  auto r = ct(1); // call the function
86  
87  std::function<property_type(ParameterT...)> f = ct;
88 */
89 }
90
91 template <typename PropertyT>
92 void bind_property(OC::OCServer& server, PropertyT& property, const std::string& binding_name, const property_type& pt, const property_attribute& pas)
93 {
94 }
95
96 }} // namespace OC::OCReflect
97
98 class light
99 {
100  bool m_powered; 
101  int m_level;
102  int m_color;
103
104  public:
105  std::string manufacturer;
106
107  public:
108  light()
109   : m_powered(false),
110     m_level(0),
111     m_color(0),
112     manufacturer("Integrated Electronics")
113  {}
114
115  public:
116  void update_things()                                                           { std::cout << "light::update_things()\n"; }
117
118  void set_powered(const bool new_state)             { m_powered = new_state; }
119  bool get_powered() const                           { return m_powered; }
120
121  void set_level(const int new_level, int color)     { m_level = new_level; m_color = color; }
122  int get_level() const                              { return m_level; }
123
124  /* An example of server-side service binding. Note that this does not need to be a 
125  member function: for classes you do not have access to, you can accomplish this with 
126  a free function: */
127  public:
128  void bindTo(OC::OCServer& server, const std::string& base_URI)
129  {
130                 using OC::OCReflect::method_signature;
131                 using OC::OCReflect::method_binding;
132                 using OC::OCReflect::property_signature;
133                 using OC::OCReflect::property_binding;
134                 using OC::OCReflect::bind_service;
135                 using OC::OCReflect::bind_property;
136
137                 using OC::OCReflect::property_type;
138
139                 server.registerResource(this, base_URI);
140
141                                 // Bind a nullary method:
142                                 bind_service(   server, 
143                                                                 this,
144                                                                 &light::update_things,
145                                                                 "updateThings",
146                                                                 property_type::nil,
147                                                                 property_type::nil);
148
149                                 // Bind an unary method:
150                                 bind_service(   server,
151                                                                 this, &light::set_powered,
152                                                                 "setPowered",
153                                                                 property_type::nil,
154                                                                 property_type::boolean);
155
156                 // Example to map setLevel method using the canonical way in one step:
157                 bind_service(
158                                 server,                         // server to bind with
159                                 this,                           // instance to bind
160                                 &light::set_level,              // method to bind
161                                 "setLevel",                     // service name
162                                 property_type::nil,             // input type
163                                 property_type::integer,         // parameter list starts (level)
164                                 property_type::integer);        // parameter list (color) 
165
166
167                 bind_service(server, this, &light::get_level, "getLevel",
168                                            property_type::integer);
169
170                 bind_service(server, this, &light::get_powered, "isPowered",
171                                            property_type::boolean);
172
173                 bind_service(server, this, &light::set_powered, "setPowered",
174                                            property_type::nil,
175                                            property_type::boolean);
176
177                 // Map powered() as a service:
178                 method_signature m_setPowered(
179                         property_type::nil,                     // return type
180                         property_type::boolean                  // parameter list (here, just arity 1)
181                 );
182
183                 // JFW: below is to say a wrapper for: std::bind(&light::set_powered, this); we'll need
184                 // to pretty these up:
185                 OC::OCReflect::bound_function f = 
186                         [](const OC::OCReflect::property_vector& args) -> OC::OCReflect::property 
187                             { return OC::OCReflect::make_property::apply(nullptr, "ret"); };
188
189                 method_binding b_setPowered(
190                         "setPowered",           // name to bind with service URL
191                         f,                      // function to bind to the service
192                         m_setPowered);          // method signature (metadata)
193
194                 server.bind(b_setPowered);      // request binding
195 /*
196                 // Example to bind a read-only property in individual steps:
197                 property_signature p_manufacturer_signature(property_type::string, OC::OCReflect::property_attribute::r); // read-only
198
199                 OC::OCReflect::named_property_binding p_manufacturer("manufacturer", p_manufacturer_signature);
200
201                 property_binding b_manufacturer(
202                         this->manufacturer,
203                         p_manufacturer);
204
205                 server.bind(b_manufacturer);
206
207                 // The canonical way to bind a property to a server in one step:
208                 bind_property(
209                                 server,                                      // server to bind to
210                                 this->manufacturer,                          // pointer to property
211                                 "manufacturer",                              // property binding name
212                                 OC::OCReflect::property_type::string,        // property
213                                 OC::OCReflect::property_attribute::r         // type decoration
214                 );
215 */
216         }
217 };
218
219 void show_bindings(const OC::OCServer& server)
220 {
221  using namespace std;
222
223  const auto& methods = server.methods();
224
225  cout << "Bound methods:\n";
226  for(const auto& m : methods)
227   {
228     cout << m.first << ':' << m.second << '\n'; 
229   }
230 }
231
232 int main()
233 {
234  OC::OCServer server;
235
236  try
237   {
238         light l;
239         l.bindTo(server, "/foo/");
240   }
241  catch(OC::OCReflect::reflection_exception& e)
242   {
243         std::cerr << "Oops: " << e.what() << '\n';
244   }
245
246  show_bindings(server);
247 }