Fawkes API  Fawkes Development Version
message_register.h
1 
2 /***************************************************************************
3  * message_register.h - Protobuf stream protocol - message register
4  *
5  * Created: Fri Feb 01 15:43:36 2013
6  * Copyright 2013 Tim Niemueller [www.niemueller.de]
7  ****************************************************************************/
8 
9 /* Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * - Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  * - Redistributions in binary form must reproduce the above copyright
16  * notice, this list of conditions and the following disclaimer in
17  * the documentation and/or other materials provided with the
18  * distribution.
19  * - Neither the name of the authors nor the names of its contributors
20  * may be used to endorse or promote products derived from this
21  * software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
28  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34  * OF THE POSSIBILITY OF SUCH DAMAGE.
35  */
36 
37 #ifndef __PROTOBUF_COMM_MESSAGE_REGISTER_H_
38 #define __PROTOBUF_COMM_MESSAGE_REGISTER_H_
39 
40 #include <protobuf_comm/frame_header.h>
41 
42 #include <type_traits>
43 #include <google/protobuf/message.h>
44 #include <google/protobuf/descriptor.h>
45 #include <boost/utility.hpp>
46 #include <boost/thread/mutex.hpp>
47 
48 #include <map>
49 #include <cstdint>
50 #include <stdexcept>
51 #include <memory>
52 #include <limits>
53 #include <mutex>
54 
55 namespace google {
56  namespace protobuf {
57  namespace compiler {
58  class Importer;
59  class DiskSourceTree;
60  }
61  }
62 }
63 
64 namespace protobuf_comm {
65 #if 0 /* just to make Emacs auto-indent happy */
66 }
67 #endif
68 
69 class MessageRegister : boost::noncopyable
70 {
71  public:
73  MessageRegister(std::vector<std::string> &proto_path);
74  ~MessageRegister();
75 
76  void add_message_type(std::string msg_type);
77 
78  /** Add a new message type.
79  * The template parameter must be a sub-class of google::protobuf::Message.
80  * An instance is spawned and kept internally to spawn more on incoming messages.
81  * @param component_id ID of component this message type belongs to
82  * @param msg_type message type
83  */
84  template <class MT>
85  typename std::enable_if<std::is_base_of<google::protobuf::Message, MT>::value, void>::type
86  add_message_type(uint16_t component_id, uint16_t msg_type)
87  {
88  KeyType key(component_id, msg_type);
89  if (message_by_comp_type_.find(key) != message_by_comp_type_.end()) {
90 #if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6))
91  std::string msg = "Message type " + std::to_string((long long)component_id) + ":" +
92  std::to_string((long long)msg_type) + " already registered";
93 #else
94  std::string msg = "Message type " + std::to_string(component_id) + ":" +
95  std::to_string(msg_type) + " already registered";
96 #endif
97  throw std::runtime_error(msg);
98  }
99  MT *m = new MT();
100  message_by_comp_type_[key] = m;
101  message_by_typename_[m->GetDescriptor()->full_name()] = m;
102  }
103 
104  /** Add a new message type.
105  * The template parameter must be a sub-class of google::protobuf::Message.
106  * An instance is spawned and kept internally to spawn more on incoming messages.
107  */
108  template <class MT>
109  typename std::enable_if<std::is_base_of<google::protobuf::Message, MT>::value, void>::type
111  {
112  MT m;
113  const google::protobuf::Descriptor *desc = m.GetDescriptor();
114  KeyType key = key_from_desc(desc);
115  if (message_by_comp_type_.find(key) != message_by_comp_type_.end()) {
116 #if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6))
117  std::string msg = "Message type " + std::to_string((long long int)key.first) + ":" +
118  std::to_string((long long int)key.second) + " already registered";
119 #else
120  std::string msg = "Message type " + std::to_string(key.first) + ":" +
121  std::to_string(key.second) + " already registered";
122 #endif
123  throw std::runtime_error(msg);
124  }
125  MT *new_m = new MT();
126  message_by_comp_type_[key] = new_m;
127  message_by_typename_[new_m->GetTypeName()] = new_m;
128  }
129 
130  void remove_message_type(uint16_t component_id, uint16_t msg_type);
131 
132  std::shared_ptr<google::protobuf::Message>
133  new_message_for(uint16_t component_id, uint16_t msg_type);
134 
135  std::shared_ptr<google::protobuf::Message>
136  new_message_for(std::string &full_name);
137 
138  void serialize(uint16_t component_id, uint16_t msg_type,
139  google::protobuf::Message &msg,
140  frame_header_t &frame_header,
141  message_header_t &message_header,
142  std::string &data);
143  std::shared_ptr<google::protobuf::Message>
144  deserialize(frame_header_t &frame_header,
145  message_header_t &message_header,
146  void *data);
147 
148  /** Mapping from message type to load error message. */
149  typedef std::multimap<std::string, std::string> LoadFailMap;
150 
151  /** Get failure messages from loading.
152  * If the proto path constructor is used this function returns a list
153  * of loading errors after construction.
154  * @return map of loading failures
155  */
156  const LoadFailMap & load_failures() const
157  { return failed_to_load_types_; }
158 
159  private: // members
160  typedef std::pair<uint16_t, uint16_t> KeyType;
161  typedef std::map<KeyType, google::protobuf::Message *> TypeMap;
162  typedef std::map<std::string, google::protobuf::Message *> TypeNameMap;
163 
164  KeyType key_from_desc(const google::protobuf::Descriptor *desc);
165  google::protobuf::Message * create_msg(std::string &msg_type);
166 
167  std::mutex maps_mutex_;
168  TypeMap message_by_comp_type_;
169  TypeNameMap message_by_typename_;
170 
171  google::protobuf::compiler::DiskSourceTree *pb_srctree_;
172  google::protobuf::compiler::Importer *pb_importer_;
173  google::protobuf::MessageFactory *pb_factory_;
174  std::multimap<std::string, std::string> failed_to_load_types_;
175 };
176 
177 } // end namespace protobuf_comm
178 
179 
180 #endif
std::enable_if< std::is_base_of< google::protobuf::Message, MT >::value, void >::type add_message_type(uint16_t component_id, uint16_t msg_type)
Add a new message type.
Register to map msg type numbers to Protobuf messages.
Network framing header.
Definition: frame_header.h:74
const LoadFailMap & load_failures() const
Get failure messages from loading.
std::multimap< std::string, std::string > LoadFailMap
Mapping from message type to load error message.
Network message header.
Definition: frame_header.h:99
std::enable_if< std::is_base_of< google::protobuf::Message, MT >::value, void >::type add_message_type()
Add a new message type.