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 <google/protobuf/descriptor.h>
41 #include <google/protobuf/message.h>
42 #include <protobuf_comm/frame_header.h>
43 
44 #include <boost/thread/mutex.hpp>
45 #include <boost/utility.hpp>
46 #include <cstdint>
47 #include <limits>
48 #include <map>
49 #include <memory>
50 #include <mutex>
51 #include <stdexcept>
52 #include <type_traits>
53 
54 namespace google {
55 namespace protobuf {
56 namespace compiler {
57 class Importer;
58 class DiskSourceTree;
59 } // namespace compiler
60 } // namespace protobuf
61 } // namespace google
62 
63 namespace protobuf_comm {
64 
65 class MessageRegister : boost::noncopyable
66 {
67 public:
69  MessageRegister(const std::vector<std::string> &proto_path);
71 
72  void add_message_type(std::string msg_type);
73 
74  /** Add a new message type.
75  * The template parameter must be a sub-class of google::protobuf::Message.
76  * An instance is spawned and kept internally to spawn more on incoming messages.
77  * @param component_id ID of component this message type belongs to
78  * @param msg_type message type
79  */
80  template <class MT>
81  typename std::enable_if<std::is_base_of<google::protobuf::Message, MT>::value, void>::type
82  add_message_type(uint16_t component_id, uint16_t msg_type)
83  {
84  KeyType key(component_id, msg_type);
85  if (message_by_comp_type_.find(key) != message_by_comp_type_.end()) {
86 #if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6))
87  std::string msg = "Message type " + std::to_string((long long)component_id) + ":"
88  + std::to_string((long long)msg_type) + " already registered";
89 #else
90  std::string msg = "Message type " + std::to_string(component_id) + ":"
91  + std::to_string(msg_type) + " already registered";
92 #endif
93  throw std::runtime_error(msg);
94  }
95  MT *m = new MT();
96  message_by_comp_type_[key] = m;
97  message_by_typename_[m->GetDescriptor()->full_name()] = m;
98  }
99 
100  /** Add a new message type.
101  * The template parameter must be a sub-class of google::protobuf::Message.
102  * An instance is spawned and kept internally to spawn more on incoming messages.
103  */
104  template <class MT>
105  typename std::enable_if<std::is_base_of<google::protobuf::Message, MT>::value, void>::type
107  {
108  MT m;
109  const google::protobuf::Descriptor *desc = m.GetDescriptor();
110  KeyType key = key_from_desc(desc);
111  if (message_by_comp_type_.find(key) != message_by_comp_type_.end()) {
112 #if defined(__GNUC__) && (__GNUC__ < 4 || (__GNUC__ == 4 && __GNUC_MINOR__ < 6))
113  std::string msg = "Message type " + std::to_string((long long int)key.first) + ":"
114  + std::to_string((long long int)key.second) + " already registered";
115 #else
116  std::string msg = "Message type " + std::to_string(key.first) + ":"
117  + std::to_string(key.second) + " already registered";
118 #endif
119  throw std::runtime_error(msg);
120  }
121  MT *new_m = new MT();
122  message_by_comp_type_[key] = new_m;
123  message_by_typename_[new_m->GetTypeName()] = new_m;
124  }
125 
126  void remove_message_type(uint16_t component_id, uint16_t msg_type);
127 
128  std::shared_ptr<google::protobuf::Message> new_message_for(uint16_t component_id,
129  uint16_t msg_type);
130 
131  std::shared_ptr<google::protobuf::Message> new_message_for(const std::string &full_name);
132 
133  void serialize(uint16_t component_id,
134  uint16_t msg_type,
135  const google::protobuf::Message &msg,
136  frame_header_t & frame_header,
137  message_header_t & message_header,
138  std::string & data);
139  std::shared_ptr<google::protobuf::Message>
140  deserialize(frame_header_t &frame_header, message_header_t &message_header, void *data);
141 
142  /** Mapping from message type to load error message. */
143  typedef std::multimap<std::string, std::string> LoadFailMap;
144 
145  /** Get failure messages from loading.
146  * If the proto path constructor is used this function returns a list
147  * of loading errors after construction.
148  * @return map of loading failures
149  */
150  const LoadFailMap &
151  load_failures() const
152  {
153  return failed_to_load_types_;
154  }
155 
156 private: // members
157  typedef std::pair<uint16_t, uint16_t> KeyType;
158  typedef std::map<KeyType, google::protobuf::Message *> TypeMap;
159  typedef std::map<std::string, google::protobuf::Message *> TypeNameMap;
160 
161  KeyType key_from_desc(const google::protobuf::Descriptor *desc);
162  google::protobuf::Message *create_msg(const std::string &msg_type);
163 
164  std::mutex maps_mutex_;
165  TypeMap message_by_comp_type_;
166  TypeNameMap message_by_typename_;
167 
168  google::protobuf::compiler::DiskSourceTree *pb_srctree_;
169  google::protobuf::compiler::Importer * pb_importer_;
170  google::protobuf::MessageFactory * pb_factory_;
171  std::multimap<std::string, std::string> failed_to_load_types_;
172 };
173 
174 } // end namespace protobuf_comm
175 
176 #endif
protobuf_comm::MessageRegister::serialize
void serialize(uint16_t component_id, uint16_t msg_type, const google::protobuf::Message &msg, frame_header_t &frame_header, message_header_t &message_header, std::string &data)
Serialize a message.
Definition: message_register.cpp:274
protobuf_comm::MessageRegister::MessageRegister
MessageRegister()
Constructor.
Definition: message_register.cpp:60
protobuf_comm::MessageRegister
Definition: message_register.h:64
protobuf_comm::MessageRegister::load_failures
const LoadFailMap & load_failures() const
Get failure messages from loading.
Definition: message_register.h:150
protobuf_comm::message_header_t
Network message header.
Definition: frame_header.h:100
protobuf_comm::frame_header_t
Network framing header.
Definition: frame_header.h:74
protobuf_comm::MessageRegister::remove_message_type
void remove_message_type(uint16_t component_id, uint16_t msg_type)
Remove the given message type.
Definition: message_register.cpp:180
protobuf_comm::MessageRegister::deserialize
std::shared_ptr< google::protobuf::Message > deserialize(frame_header_t &frame_header, message_header_t &message_header, void *data)
Deserialize message.
Definition: message_register.cpp:314
protobuf_comm::MessageRegister::~MessageRegister
~MessageRegister()
Destructor.
Definition: message_register.cpp:110
protobuf_comm::MessageRegister::add_message_type
std::enable_if< std::is_base_of< google::protobuf::Message, MT >::value, void >::type add_message_type()
Add a new message type.
Definition: message_register.h:105
protobuf_comm::MessageRegister::new_message_for
std::shared_ptr< google::protobuf::Message > new_message_for(uint16_t component_id, uint16_t msg_type)
Create a new message instance.
Definition: message_register.cpp:220
protobuf_comm::MessageRegister::LoadFailMap
std::multimap< std::string, std::string > LoadFailMap
Mapping from message type to load error message.
Definition: message_register.h:142