DCCL v4
dynamic_protobuf_manager.cpp
1 // Copyright 2012-2023:
2 // GobySoft, LLC (2013-)
3 // Massachusetts Institute of Technology (2007-2014)
4 // Community contributors (see AUTHORS file)
5 // File authors:
6 // Toby Schneider <toby@gobysoft.org>
7 //
8 //
9 // This file is part of the Dynamic Compact Control Language Library
10 // ("DCCL").
11 //
12 // DCCL is free software: you can redistribute it and/or modify
13 // it under the terms of the GNU Lesser General Public License as published by
14 // the Free Software Foundation, either version 2.1 of the License, or
15 // (at your option) any later version.
16 //
17 // DCCL is distributed in the hope that it will be useful,
18 // but WITHOUT ANY WARRANTY; without even the implied warranty of
19 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 // GNU Lesser General Public License for more details.
21 //
22 // You should have received a copy of the GNU Lesser General Public License
23 // along with DCCL. If not, see <http://www.gnu.org/licenses/>.
24 #include <sstream>
25 
26 #include "dynamic_protobuf_manager.h"
27 #include "exception.h"
28 #include "logger.h"
29 
30 std::shared_ptr<dccl::DynamicProtobufManager> dccl::DynamicProtobufManager::inst_;
31 
32 //
33 // STATIC
34 //
35 const google::protobuf::Descriptor*
36 dccl::DynamicProtobufManager::find_descriptor(const std::string& protobuf_type_name,
37  bool user_pool_first)
38 {
39  DCCL_LOCK_DYNAMIC_PROTOBUF_MANAGER_MUTEX
40  const google::protobuf::Descriptor* desc = nullptr;
41  if (user_pool_first)
42  {
43  // try the user pool
44  desc = get_instance()->user_descriptor_pool_->FindMessageTypeByName(protobuf_type_name);
45  if (desc)
46  return desc;
47  }
48 
49  // try the generated pool
50  desc = google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(
51  protobuf_type_name);
52  if (desc)
53  return desc;
54 
55  if (!user_pool_first)
56  {
57  // try the user pool
58  desc = get_instance()->user_descriptor_pool_->FindMessageTypeByName(protobuf_type_name);
59  }
60 
61  return desc;
62 }
63 
64 std::shared_ptr<google::protobuf::Message>
65 dccl::DynamicProtobufManager::new_protobuf_message(const google::protobuf::Descriptor* desc)
66 {
67  DCCL_LOCK_DYNAMIC_PROTOBUF_MANAGER_MUTEX
68  return new_protobuf_message<std::shared_ptr<google::protobuf::Message>>(desc);
69 }
70 
71 std::shared_ptr<google::protobuf::Message>
72 dccl::DynamicProtobufManager::new_protobuf_message(const std::string& protobuf_type_name)
73 {
74  DCCL_LOCK_DYNAMIC_PROTOBUF_MANAGER_MUTEX
75  return new_protobuf_message<std::shared_ptr<google::protobuf::Message>>(protobuf_type_name);
76 }
77 
79  std::shared_ptr<google::protobuf::DescriptorDatabase> database)
80 {
81  DCCL_LOCK_DYNAMIC_PROTOBUF_MANAGER_MUTEX
82  get_instance()->databases_.push_back(database);
83  get_instance()->update_databases();
84 }
85 
87 {
88  DCCL_LOCK_DYNAMIC_PROTOBUF_MANAGER_MUTEX
89 
90  if (!get_instance()->disk_source_tree_)
91  throw(std::runtime_error(
92  "Must called enable_compilation() before loading proto files directly"));
93 
94  get_instance()->disk_source_tree_->MapPath("", path);
95 }
96 
97 void* dccl::DynamicProtobufManager::load_from_shared_lib(const std::string& shared_lib_path)
98 {
99  DCCL_LOCK_DYNAMIC_PROTOBUF_MANAGER_MUTEX
100  void* handle = dlopen(shared_lib_path.c_str(), RTLD_LAZY);
101  if (handle)
102  get_instance()->dl_handles_.push_back(handle);
103  return handle;
104 }
105 
111 const google::protobuf::FileDescriptor*
112 dccl::DynamicProtobufManager::load_from_proto_file(const std::string& protofile_absolute_path)
113 {
114  DCCL_LOCK_DYNAMIC_PROTOBUF_MANAGER_MUTEX
115 
116  if (!get_instance()->source_database_)
117  throw(dccl::Exception(
118  "Must called enable_compilation() before loading proto files directly"));
119 
120  return get_instance()->user_descriptor_pool_->FindFileByName(protofile_absolute_path);
121 }
122 
123 const google::protobuf::FileDescriptor*
124 dccl::DynamicProtobufManager::add_protobuf_file(const google::protobuf::FileDescriptorProto& proto)
125 {
126  DCCL_LOCK_DYNAMIC_PROTOBUF_MANAGER_MUTEX
127  get_instance()->simple_database_->Add(proto);
128 
129  const google::protobuf::FileDescriptor* return_desc =
130  get_instance()->user_descriptor_pool_->FindFileByName(proto.name());
131  return return_desc;
132 }
133 
134 //
135 // NON STATIC
136 //
137 
138 void dccl::DynamicProtobufManager::enable_disk_source_database()
139 {
140  if (disk_source_tree_)
141  return;
142 
143  disk_source_tree_.reset(new google::protobuf::compiler::DiskSourceTree);
144  source_database_.reset(
145  new google::protobuf::compiler::SourceTreeDescriptorDatabase(disk_source_tree_.get()));
146  error_collector_.reset(new DLogMultiFileErrorCollector);
147 
148  source_database_->RecordErrorsTo(error_collector_.get());
149  disk_source_tree_->MapPath("/", "/");
150  disk_source_tree_->MapPath("", "");
151  add_database(source_database_);
152 }
153 
154 // DLogMultiFileErrorCollector
155 void dccl::DynamicProtobufManager::DLogMultiFileErrorCollector::AddError(
156  const std::string& filename, int line, int column, const std::string& message)
157 {
158  std::stringstream ss;
159  ss << "File: " << filename << " has error (line: " << line << ", column: " << column
160  << "):" << message;
161 
162  throw(dccl::Exception(ss.str()));
163 }
dccl::DynamicProtobufManager::add_protobuf_file
static const google::protobuf::FileDescriptor * add_protobuf_file(const google::protobuf::FileDescriptorProto &proto)
Add a protobuf file defined in a google::protobuf::FileDescriptorProto.
Definition: dynamic_protobuf_manager.cpp:124
dccl::Exception
Exception class for DCCL.
Definition: exception.h:46
dccl::DynamicProtobufManager::load_from_shared_lib
static void * load_from_shared_lib(const std::string &shared_lib_path)
Load compiled .proto files from a UNIX shared library (i.e. *.so or *.dylib)
Definition: dynamic_protobuf_manager.cpp:97
dccl::DynamicProtobufManager::add_database
static void add_database(std::shared_ptr< google::protobuf::DescriptorDatabase > database)
Add a Google Protobuf DescriptorDatabase to the set of databases searched for Message Descriptors.
Definition: dynamic_protobuf_manager.cpp:78
dccl::DynamicProtobufManager::load_from_proto_file
static const google::protobuf::FileDescriptor * load_from_proto_file(const std::string &protofile_absolute_path)
Load a message from a .proto file on the disk. enable_compilation() must be called first.
Definition: dynamic_protobuf_manager.cpp:112
dccl::DynamicProtobufManager::add_include_path
static void add_include_path(const std::string &path)
Add a path for searching for import messages when loading .proto files using load_from_proto_file()
Definition: dynamic_protobuf_manager.cpp:86
dccl::DynamicProtobufManager::new_protobuf_message
static GoogleProtobufMessagePointer new_protobuf_message(const std::string &protobuf_type_name, bool user_pool_first=false)
Create a new (empty) Google Protobuf message of a given type by name.
Definition: dynamic_protobuf_manager.h:76
dccl::DynamicProtobufManager::find_descriptor
static const google::protobuf::Descriptor * find_descriptor(const std::string &protobuf_type_name, bool user_pool_first=false)
Finds the Google Protobuf Descriptor (essentially a meta-class for a given Message) from a given Mess...
Definition: dynamic_protobuf_manager.cpp:36