DCCL v5
Loading...
Searching...
No Matches
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
29std::shared_ptr<dccl::DynamicProtobufManager> dccl::DynamicProtobufManager::inst_;
30
31//
32// STATIC
33//
34const google::protobuf::Descriptor*
35dccl::DynamicProtobufManager::find_descriptor(const std::string& protobuf_type_name,
36 bool user_pool_first)
37{
38 DCCL_LOCK_DYNAMIC_PROTOBUF_MANAGER_MUTEX
39 const google::protobuf::Descriptor* desc = nullptr;
40 if (user_pool_first)
41 {
42 // try the user pool
43 desc = get_instance()->user_descriptor_pool_->FindMessageTypeByName(protobuf_type_name);
44 if (desc)
45 return desc;
46 }
47
48 // try the generated pool
49 desc = google::protobuf::DescriptorPool::generated_pool()->FindMessageTypeByName(
50 protobuf_type_name);
51 if (desc)
52 return desc;
53
54 if (!user_pool_first)
55 {
56 // try the user pool
57 desc = get_instance()->user_descriptor_pool_->FindMessageTypeByName(protobuf_type_name);
58 }
59
60 return desc;
61}
62
63std::shared_ptr<google::protobuf::Message>
64dccl::DynamicProtobufManager::new_protobuf_message(const google::protobuf::Descriptor* desc)
65{
66 DCCL_LOCK_DYNAMIC_PROTOBUF_MANAGER_MUTEX
67 return new_protobuf_message<std::shared_ptr<google::protobuf::Message>>(desc);
68}
69
70std::shared_ptr<google::protobuf::Message>
71dccl::DynamicProtobufManager::new_protobuf_message(const std::string& protobuf_type_name)
72{
73 DCCL_LOCK_DYNAMIC_PROTOBUF_MANAGER_MUTEX
74 return new_protobuf_message<std::shared_ptr<google::protobuf::Message>>(protobuf_type_name);
75}
76
78 std::shared_ptr<google::protobuf::DescriptorDatabase> database)
79{
80 DCCL_LOCK_DYNAMIC_PROTOBUF_MANAGER_MUTEX
81 get_instance()->databases_.push_back(database);
82 get_instance()->update_databases();
83}
84
86{
87 DCCL_LOCK_DYNAMIC_PROTOBUF_MANAGER_MUTEX
88
89 if (!get_instance()->disk_source_tree_)
90 throw(std::runtime_error(
91 "Must called enable_compilation() before loading proto files directly"));
92
93 get_instance()->disk_source_tree_->MapPath("", path);
94}
95
96void* dccl::DynamicProtobufManager::load_from_shared_lib(const std::string& shared_lib_path)
97{
98 DCCL_LOCK_DYNAMIC_PROTOBUF_MANAGER_MUTEX
99 void* handle = dlopen(shared_lib_path.c_str(), RTLD_LAZY);
100 if (handle)
101 get_instance()->dl_handles_.push_back(handle);
102 return handle;
103}
104
110const google::protobuf::FileDescriptor*
111dccl::DynamicProtobufManager::load_from_proto_file(const std::string& protofile_absolute_path)
112{
113 DCCL_LOCK_DYNAMIC_PROTOBUF_MANAGER_MUTEX
114
115 if (!get_instance()->source_database_)
116 throw(dccl::Exception(
117 "Must called enable_compilation() before loading proto files directly"));
118
119 return get_instance()->user_descriptor_pool_->FindFileByName(protofile_absolute_path);
120}
121
122const google::protobuf::FileDescriptor*
123dccl::DynamicProtobufManager::add_protobuf_file(const google::protobuf::FileDescriptorProto& proto)
124{
125 DCCL_LOCK_DYNAMIC_PROTOBUF_MANAGER_MUTEX
126 get_instance()->simple_database_->Add(proto);
127
128 const google::protobuf::FileDescriptor* return_desc =
129 get_instance()->user_descriptor_pool_->FindFileByName(proto.name());
130 return return_desc;
131}
132
133//
134// NON STATIC
135//
136
137void dccl::DynamicProtobufManager::enable_disk_source_database()
138{
139 if (disk_source_tree_)
140 return;
141
142 disk_source_tree_.reset(new google::protobuf::compiler::DiskSourceTree);
143 source_database_.reset(
144 new google::protobuf::compiler::SourceTreeDescriptorDatabase(disk_source_tree_.get()));
145 error_collector_.reset(new DLogMultiFileErrorCollector);
146
147 source_database_->RecordErrorsTo(error_collector_.get());
148 disk_source_tree_->MapPath("/", "/");
149 disk_source_tree_->MapPath("", "");
150 add_database(source_database_);
151}
152
153// DLogMultiFileErrorCollector
154#if GOOGLE_PROTOBUF_VERSION >= 4022000
155void dccl::DynamicProtobufManager::DLogMultiFileErrorCollector::RecordError(
156 absl::string_view filename, int line, int column, absl::string_view message)
157#else
158void dccl::DynamicProtobufManager::DLogMultiFileErrorCollector::AddError(
159 const std::string& filename, int line, int column, const std::string& message)
160#endif
161{
162 std::stringstream ss;
163 ss << "File: " << filename << " has error (line: " << line << ", column: " << column
164 << "):" << message;
165
166 throw(dccl::Exception(ss.str()));
167}
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.
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()
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)
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...
static const google::protobuf::FileDescriptor * add_protobuf_file(const google::protobuf::FileDescriptorProto &proto)
Add a protobuf file defined in a google::protobuf::FileDescriptorProto.
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.
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.
Exception class for DCCL.
Definition exception.h:47