• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.  All rights reserved.
3 // https://developers.google.com/protocol-buffers/
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are
7 // met:
8 //
9 //     * Redistributions of source code must retain the above copyright
10 // notice, this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above
12 // copyright notice, this list of conditions and the following disclaimer
13 // in the documentation and/or other materials provided with the
14 // distribution.
15 //     * Neither the name of Google Inc. nor the names of its
16 // contributors may be used to endorse or promote products derived from
17 // this software without specific prior written permission.
18 //
19 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30 
31 #include <google/protobuf/util/internal/type_info.h>
32 
33 #include <map>
34 #include <set>
35 
36 #include <google/protobuf/stubs/common.h>
37 #include <google/protobuf/type.pb.h>
38 #include <google/protobuf/util/internal/utility.h>
39 #include <google/protobuf/stubs/stringpiece.h>
40 #include <google/protobuf/stubs/map_util.h>
41 #include <google/protobuf/stubs/status.h>
42 #include <google/protobuf/stubs/statusor.h>
43 
44 namespace google {
45 namespace protobuf {
46 namespace util {
47 namespace converter {
48 
49 namespace {
50 // A TypeInfo that looks up information provided by a TypeResolver.
51 class TypeInfoForTypeResolver : public TypeInfo {
52  public:
TypeInfoForTypeResolver(TypeResolver * type_resolver)53   explicit TypeInfoForTypeResolver(TypeResolver* type_resolver)
54       : type_resolver_(type_resolver) {}
55 
~TypeInfoForTypeResolver()56   virtual ~TypeInfoForTypeResolver() {
57     DeleteCachedTypes(&cached_types_);
58     DeleteCachedTypes(&cached_enums_);
59   }
60 
ResolveTypeUrl(StringPiece type_url) const61   virtual util::StatusOr<const google::protobuf::Type*> ResolveTypeUrl(
62       StringPiece type_url) const {
63     map<StringPiece, StatusOrType>::iterator it = cached_types_.find(type_url);
64     if (it != cached_types_.end()) {
65       return it->second;
66     }
67     // Stores the string value so it can be referenced using StringPiece in the
68     // cached_types_ map.
69     const string& string_type_url =
70         *string_storage_.insert(type_url.ToString()).first;
71     google::protobuf::scoped_ptr<google::protobuf::Type> type(new google::protobuf::Type());
72     util::Status status =
73         type_resolver_->ResolveMessageType(string_type_url, type.get());
74     StatusOrType result =
75         status.ok() ? StatusOrType(type.release()) : StatusOrType(status);
76     cached_types_[string_type_url] = result;
77     return result;
78   }
79 
GetTypeByTypeUrl(StringPiece type_url) const80   virtual const google::protobuf::Type* GetTypeByTypeUrl(
81       StringPiece type_url) const {
82     StatusOrType result = ResolveTypeUrl(type_url);
83     return result.ok() ? result.ValueOrDie() : NULL;
84   }
85 
GetEnumByTypeUrl(StringPiece type_url) const86   virtual const google::protobuf::Enum* GetEnumByTypeUrl(
87       StringPiece type_url) const {
88     map<StringPiece, StatusOrEnum>::iterator it = cached_enums_.find(type_url);
89     if (it != cached_enums_.end()) {
90       return it->second.ok() ? it->second.ValueOrDie() : NULL;
91     }
92     // Stores the string value so it can be referenced using StringPiece in the
93     // cached_enums_ map.
94     const string& string_type_url =
95         *string_storage_.insert(type_url.ToString()).first;
96     google::protobuf::scoped_ptr<google::protobuf::Enum> enum_type(
97         new google::protobuf::Enum());
98     util::Status status =
99         type_resolver_->ResolveEnumType(string_type_url, enum_type.get());
100     StatusOrEnum result =
101         status.ok() ? StatusOrEnum(enum_type.release()) : StatusOrEnum(status);
102     cached_enums_[string_type_url] = result;
103     return result.ok() ? result.ValueOrDie() : NULL;
104   }
105 
FindField(const google::protobuf::Type * type,StringPiece camel_case_name) const106   virtual const google::protobuf::Field* FindField(
107       const google::protobuf::Type* type, StringPiece camel_case_name) const {
108     if (indexed_types_.find(type) == indexed_types_.end()) {
109       PopulateNameLookupTable(type);
110       indexed_types_.insert(type);
111     }
112     StringPiece name =
113         FindWithDefault(camel_case_name_table_, camel_case_name, StringPiece());
114     if (name.empty()) {
115       // Didn't find a mapping. Use whatever provided.
116       name = camel_case_name;
117     }
118     return FindFieldInTypeOrNull(type, name);
119   }
120 
121  private:
122   typedef util::StatusOr<const google::protobuf::Type*> StatusOrType;
123   typedef util::StatusOr<const google::protobuf::Enum*> StatusOrEnum;
124 
125   template <typename T>
DeleteCachedTypes(map<StringPiece,T> * cached_types)126   static void DeleteCachedTypes(map<StringPiece, T>* cached_types) {
127     for (typename map<StringPiece, T>::iterator it = cached_types->begin();
128          it != cached_types->end(); ++it) {
129       if (it->second.ok()) {
130         delete it->second.ValueOrDie();
131       }
132     }
133   }
134 
PopulateNameLookupTable(const google::protobuf::Type * type) const135   void PopulateNameLookupTable(const google::protobuf::Type* type) const {
136     for (int i = 0; i < type->fields_size(); ++i) {
137       const google::protobuf::Field& field = type->fields(i);
138       StringPiece name = field.name();
139       StringPiece camel_case_name = field.json_name();
140       const StringPiece* existing = InsertOrReturnExisting(
141           &camel_case_name_table_, camel_case_name, name);
142       if (existing && *existing != name) {
143         GOOGLE_LOG(WARNING) << "Field '" << name << "' and '" << *existing
144                      << "' map to the same camel case name '" << camel_case_name
145                      << "'.";
146       }
147     }
148   }
149 
150   TypeResolver* type_resolver_;
151 
152   // Stores string values that will be referenced by StringPieces in
153   // cached_types_, cached_enums_ and camel_case_name_table_.
154   mutable set<string> string_storage_;
155 
156   mutable map<StringPiece, StatusOrType> cached_types_;
157   mutable map<StringPiece, StatusOrEnum> cached_enums_;
158 
159   mutable set<const google::protobuf::Type*> indexed_types_;
160   mutable map<StringPiece, StringPiece> camel_case_name_table_;
161 };
162 }  // namespace
163 
NewTypeInfo(TypeResolver * type_resolver)164 TypeInfo* TypeInfo::NewTypeInfo(TypeResolver* type_resolver) {
165   return new TypeInfoForTypeResolver(type_resolver);
166 }
167 
168 }  // namespace converter
169 }  // namespace util
170 }  // namespace protobuf
171 }  // namespace google
172