DCCL v4
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#include "logger.h"
29
30std::shared_ptr<dccl::DynamicProtobufManager> dccl::DynamicProtobufManager::inst_;
31
32//
33// STATIC
34//
35const google::protobuf::Descriptor*
36dccl::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
64std::shared_ptr<google::protobuf::Message>
65dccl::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
71std::shared_ptr<google::protobuf::Message>
72dccl::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
97void* 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
111const google::protobuf::FileDescriptor*
112dccl::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
123const google::protobuf::FileDescriptor*
124dccl::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
138void 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
155void 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}
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