Home | History | Annotate | Download | only in internal
      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:
     53   explicit TypeInfoForTypeResolver(TypeResolver* type_resolver)
     54       : type_resolver_(type_resolver) {}
     55 
     56   virtual ~TypeInfoForTypeResolver() {
     57     DeleteCachedTypes(&cached_types_);
     58     DeleteCachedTypes(&cached_enums_);
     59   }
     60 
     61   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 
     80   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 
     86   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 
    106   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>
    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 
    135   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 
    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