Avro C++
|
00001 /* 00002 * Licensed to the Apache Software Foundation (ASF) under one 00003 * or more contributor license agreements. See the NOTICE file 00004 * distributed with this work for additional information 00005 * regarding copyright ownership. The ASF licenses this file 00006 * to you under the Apache License, Version 2.0 (the 00007 * "License"); you may not use this file except in compliance 00008 * with the License. You may obtain a copy of the License at 00009 * 00010 * http://www.apache.org/licenses/LICENSE-2.0 00011 * 00012 * Unless required by applicable law or agreed to in writing, software 00013 * distributed under the License is distributed on an "AS IS" BASIS, 00014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00015 * See the License for the specific language governing permissions and 00016 * limitations under the License. 00017 */ 00018 00019 #ifndef avro_NodeImpl_hh__ 00020 #define avro_NodeImpl_hh__ 00021 00022 #include "Config.hh" 00023 #include "GenericDatum.hh" 00024 00025 #include <limits> 00026 #include <set> 00027 #include <boost/weak_ptr.hpp> 00028 00029 #include "Node.hh" 00030 #include "NodeConcepts.hh" 00031 00032 namespace avro { 00033 00036 00037 template 00038 < 00039 class NameConcept, 00040 class LeavesConcept, 00041 class LeafNamesConcept, 00042 class SizeConcept 00043 > 00044 class NodeImpl : public Node 00045 { 00046 00047 protected: 00048 00049 NodeImpl(Type type) : 00050 Node(type), 00051 nameAttribute_(), 00052 leafAttributes_(), 00053 leafNameAttributes_(), 00054 sizeAttribute_() 00055 { } 00056 00057 NodeImpl(Type type, 00058 const NameConcept &name, 00059 const LeavesConcept &leaves, 00060 const LeafNamesConcept &leafNames, 00061 const SizeConcept &size) : 00062 Node(type), 00063 nameAttribute_(name), 00064 leafAttributes_(leaves), 00065 leafNameAttributes_(leafNames), 00066 sizeAttribute_(size) 00067 { } 00068 00069 void swap(NodeImpl& impl) { 00070 std::swap(nameAttribute_, impl.nameAttribute_); 00071 std::swap(leafAttributes_, impl.leafAttributes_); 00072 std::swap(leafNameAttributes_, impl.leafNameAttributes_); 00073 std::swap(sizeAttribute_, impl.sizeAttribute_); 00074 std::swap(nameIndex_, impl.nameIndex_); 00075 } 00076 00077 bool hasName() const { 00078 return NameConcept::hasAttribute; 00079 } 00080 00081 void doSetName(const Name &name) { 00082 nameAttribute_.add(name); 00083 } 00084 00085 const Name &name() const { 00086 return nameAttribute_.get(); 00087 } 00088 00089 void doAddLeaf(const NodePtr &newLeaf) { 00090 leafAttributes_.add(newLeaf); 00091 } 00092 00093 size_t leaves() const { 00094 return leafAttributes_.size(); 00095 } 00096 00097 const NodePtr &leafAt(int index) const { 00098 return leafAttributes_.get(index); 00099 } 00100 00101 void doAddName(const std::string &name) { 00102 if (! nameIndex_.add(name, leafNameAttributes_.size())) { 00103 throw Exception(boost::format("Cannot add duplicate name: %1%") % name); 00104 } 00105 leafNameAttributes_.add(name); 00106 } 00107 00108 size_t names() const { 00109 return leafNameAttributes_.size(); 00110 } 00111 00112 const std::string &nameAt(int index) const { 00113 return leafNameAttributes_.get(index); 00114 } 00115 00116 bool nameIndex(const std::string &name, size_t &index) const { 00117 return nameIndex_.lookup(name, index); 00118 } 00119 00120 void doSetFixedSize(int size) { 00121 sizeAttribute_.add(size); 00122 } 00123 00124 int fixedSize() const { 00125 return sizeAttribute_.get(); 00126 } 00127 00128 virtual bool isValid() const = 0; 00129 00130 void printBasicInfo(std::ostream &os) const; 00131 00132 void setLeafToSymbolic(int index, const NodePtr &node); 00133 00134 SchemaResolution furtherResolution(const Node &reader) const { 00135 SchemaResolution match = RESOLVE_NO_MATCH; 00136 00137 if (reader.type() == AVRO_SYMBOLIC) { 00138 00139 // resolve the symbolic type, and check again 00140 const NodePtr &node = reader.leafAt(0); 00141 match = resolve(*node); 00142 } 00143 else if(reader.type() == AVRO_UNION) { 00144 00145 // in this case, need to see if there is an exact match for the 00146 // writer's type, or if not, the first one that can be promoted to a 00147 // match 00148 00149 for(size_t i= 0; i < reader.leaves(); ++i) { 00150 00151 const NodePtr &node = reader.leafAt(i); 00152 SchemaResolution thisMatch = resolve(*node); 00153 00154 // if matched then the search is done 00155 if(thisMatch == RESOLVE_MATCH) { 00156 match = thisMatch; 00157 break; 00158 } 00159 00160 // thisMatch is either no match, or promotable, this will set match to 00161 // promotable if it hasn't been set already 00162 if (match == RESOLVE_NO_MATCH) { 00163 match = thisMatch; 00164 } 00165 } 00166 } 00167 00168 return match; 00169 } 00170 00171 NameConcept nameAttribute_; 00172 LeavesConcept leafAttributes_; 00173 LeafNamesConcept leafNameAttributes_; 00174 SizeConcept sizeAttribute_; 00175 concepts::NameIndexConcept<LeafNamesConcept> nameIndex_; 00176 }; 00177 00178 typedef concepts::NoAttribute<Name> NoName; 00179 typedef concepts::SingleAttribute<Name> HasName; 00180 00181 typedef concepts::NoAttribute<NodePtr> NoLeaves; 00182 typedef concepts::SingleAttribute<NodePtr> SingleLeaf; 00183 typedef concepts::MultiAttribute<NodePtr> MultiLeaves; 00184 00185 typedef concepts::NoAttribute<std::string> NoLeafNames; 00186 typedef concepts::MultiAttribute<std::string> LeafNames; 00187 00188 typedef concepts::NoAttribute<int> NoSize; 00189 typedef concepts::SingleAttribute<int> HasSize; 00190 00191 typedef NodeImpl< NoName, NoLeaves, NoLeafNames, NoSize > NodeImplPrimitive; 00192 typedef NodeImpl< HasName, NoLeaves, NoLeafNames, NoSize > NodeImplSymbolic; 00193 00194 typedef NodeImpl< HasName, MultiLeaves, LeafNames, NoSize > NodeImplRecord; 00195 typedef NodeImpl< HasName, NoLeaves, LeafNames, NoSize > NodeImplEnum; 00196 typedef NodeImpl< NoName, SingleLeaf, NoLeafNames, NoSize > NodeImplArray; 00197 typedef NodeImpl< NoName, MultiLeaves, NoLeafNames, NoSize > NodeImplMap; 00198 typedef NodeImpl< NoName, MultiLeaves, NoLeafNames, NoSize > NodeImplUnion; 00199 typedef NodeImpl< HasName, NoLeaves, NoLeafNames, HasSize > NodeImplFixed; 00200 00201 class AVRO_DECL NodePrimitive : public NodeImplPrimitive 00202 { 00203 public: 00204 00205 explicit NodePrimitive(Type type) : 00206 NodeImplPrimitive(type) 00207 { } 00208 00209 SchemaResolution resolve(const Node &reader) const; 00210 00211 void printJson(std::ostream &os, int depth) const; 00212 00213 bool isValid() const { 00214 return true; 00215 } 00216 }; 00217 00218 class AVRO_DECL NodeSymbolic : public NodeImplSymbolic 00219 { 00220 typedef boost::weak_ptr<Node> NodeWeakPtr; 00221 00222 public: 00223 00224 NodeSymbolic() : 00225 NodeImplSymbolic(AVRO_SYMBOLIC) 00226 { } 00227 00228 explicit NodeSymbolic(const HasName &name) : 00229 NodeImplSymbolic(AVRO_SYMBOLIC, name, NoLeaves(), NoLeafNames(), NoSize()) 00230 { } 00231 00232 NodeSymbolic(const HasName &name, const NodePtr n) : 00233 NodeImplSymbolic(AVRO_SYMBOLIC, name, NoLeaves(), NoLeafNames(), NoSize()), actualNode_(n) 00234 { } 00235 SchemaResolution resolve(const Node &reader) const; 00236 00237 void printJson(std::ostream &os, int depth) const; 00238 00239 bool isValid() const { 00240 return (nameAttribute_.size() == 1); 00241 } 00242 00243 bool isSet() const { 00244 return (actualNode_.lock() != 0); 00245 } 00246 00247 NodePtr getNode() const { 00248 NodePtr node = actualNode_.lock(); 00249 if(!node) { 00250 throw Exception(boost::format("Could not follow symbol %1%") % name()); 00251 } 00252 return node; 00253 } 00254 00255 void setNode(const NodePtr &node) { 00256 actualNode_ = node; 00257 } 00258 00259 protected: 00260 00261 NodeWeakPtr actualNode_; 00262 00263 }; 00264 00265 class AVRO_DECL NodeRecord : public NodeImplRecord { 00266 std::vector<GenericDatum> defaultValues; 00267 public: 00268 NodeRecord() : NodeImplRecord(AVRO_RECORD) { } 00269 NodeRecord(const HasName &name, const MultiLeaves &fields, 00270 const LeafNames &fieldsNames, 00271 const std::vector<GenericDatum>& dv) : 00272 NodeImplRecord(AVRO_RECORD, name, fields, fieldsNames, NoSize()), 00273 defaultValues(dv) { 00274 for (size_t i = 0; i < leafNameAttributes_.size(); ++i) { 00275 if (!nameIndex_.add(leafNameAttributes_.get(i), i)) { 00276 throw Exception(boost::format( 00277 "Cannot add duplicate name: %1%") % 00278 leafNameAttributes_.get(i)); 00279 } 00280 } 00281 } 00282 00283 void swap(NodeRecord& r) { 00284 NodeImplRecord::swap(r); 00285 defaultValues.swap(r.defaultValues); 00286 } 00287 00288 SchemaResolution resolve(const Node &reader) const; 00289 00290 void printJson(std::ostream &os, int depth) const; 00291 00292 bool isValid() const { 00293 return ((nameAttribute_.size() == 1) && 00294 (leafAttributes_.size() == leafNameAttributes_.size())); 00295 } 00296 00297 const GenericDatum& defaultValueAt(int index) { 00298 return defaultValues[index]; 00299 } 00300 }; 00301 00302 class AVRO_DECL NodeEnum : public NodeImplEnum 00303 { 00304 public: 00305 00306 NodeEnum() : 00307 NodeImplEnum(AVRO_ENUM) 00308 { } 00309 00310 NodeEnum(const HasName &name, const LeafNames &symbols) : 00311 NodeImplEnum(AVRO_ENUM, name, NoLeaves(), symbols, NoSize()) 00312 { 00313 for(size_t i=0; i < leafNameAttributes_.size(); ++i) { 00314 if(!nameIndex_.add(leafNameAttributes_.get(i), i)) { 00315 throw Exception(boost::format("Cannot add duplicate name: %1%") % leafNameAttributes_.get(i)); 00316 } 00317 } 00318 } 00319 00320 SchemaResolution resolve(const Node &reader) const; 00321 00322 void printJson(std::ostream &os, int depth) const; 00323 00324 bool isValid() const { 00325 return ( 00326 (nameAttribute_.size() == 1) && 00327 (leafNameAttributes_.size() > 0) 00328 ); 00329 } 00330 }; 00331 00332 class AVRO_DECL NodeArray : public NodeImplArray 00333 { 00334 public: 00335 00336 NodeArray() : 00337 NodeImplArray(AVRO_ARRAY) 00338 { } 00339 00340 explicit NodeArray(const SingleLeaf &items) : 00341 NodeImplArray(AVRO_ARRAY, NoName(), items, NoLeafNames(), NoSize()) 00342 { } 00343 00344 SchemaResolution resolve(const Node &reader) const; 00345 00346 void printJson(std::ostream &os, int depth) const; 00347 00348 bool isValid() const { 00349 return (leafAttributes_.size() == 1); 00350 } 00351 }; 00352 00353 class AVRO_DECL NodeMap : public NodeImplMap 00354 { 00355 public: 00356 00357 NodeMap() : 00358 NodeImplMap(AVRO_MAP) 00359 { 00360 NodePtr key(new NodePrimitive(AVRO_STRING)); 00361 doAddLeaf(key); 00362 } 00363 00364 explicit NodeMap(const SingleLeaf &values) : 00365 NodeImplMap(AVRO_MAP, NoName(), values, NoLeafNames(), NoSize()) 00366 { 00367 // need to add the key for the map too 00368 NodePtr key(new NodePrimitive(AVRO_STRING)); 00369 doAddLeaf(key); 00370 00371 // key goes before value 00372 std::swap(leafAttributes_.get(0), leafAttributes_.get(1)); 00373 } 00374 00375 SchemaResolution resolve(const Node &reader) const; 00376 00377 void printJson(std::ostream &os, int depth) const; 00378 00379 bool isValid() const { 00380 return (leafAttributes_.size() == 2); 00381 } 00382 }; 00383 00384 class AVRO_DECL NodeUnion : public NodeImplUnion 00385 { 00386 public: 00387 00388 NodeUnion() : 00389 NodeImplUnion(AVRO_UNION) 00390 { } 00391 00392 explicit NodeUnion(const MultiLeaves &types) : 00393 NodeImplUnion(AVRO_UNION, NoName(), types, NoLeafNames(), NoSize()) 00394 { } 00395 00396 SchemaResolution resolve(const Node &reader) const; 00397 00398 void printJson(std::ostream &os, int depth) const; 00399 00400 bool isValid() const { 00401 std::set<std::string> seen; 00402 if (leafAttributes_.size() >= 1) { 00403 for (size_t i = 0; i < leafAttributes_.size(); ++i) { 00404 std::string name; 00405 const NodePtr& n = leafAttributes_.get(i); 00406 switch (n->type()) { 00407 case AVRO_STRING: 00408 name = "string"; 00409 break; 00410 case AVRO_BYTES: 00411 name = "bytes"; 00412 break; 00413 case AVRO_INT: 00414 name = "int"; 00415 break; 00416 case AVRO_LONG: 00417 name = "long"; 00418 break; 00419 case AVRO_FLOAT: 00420 name = "float"; 00421 break; 00422 case AVRO_DOUBLE: 00423 name = "double"; 00424 break; 00425 case AVRO_BOOL: 00426 name = "bool"; 00427 break; 00428 case AVRO_NULL: 00429 name = "null"; 00430 break; 00431 case AVRO_ARRAY: 00432 name = "array"; 00433 break; 00434 case AVRO_MAP: 00435 name = "map"; 00436 break; 00437 case AVRO_RECORD: 00438 case AVRO_ENUM: 00439 case AVRO_UNION: 00440 case AVRO_FIXED: 00441 case AVRO_SYMBOLIC: 00442 name = n->name().fullname(); 00443 break; 00444 default: 00445 return false; 00446 } 00447 if (seen.find(name) != seen.end()) { 00448 return false; 00449 } 00450 seen.insert(name); 00451 } 00452 return true; 00453 } 00454 return false; 00455 } 00456 }; 00457 00458 class AVRO_DECL NodeFixed : public NodeImplFixed 00459 { 00460 public: 00461 00462 NodeFixed() : 00463 NodeImplFixed(AVRO_FIXED) 00464 { } 00465 00466 NodeFixed(const HasName &name, const HasSize &size) : 00467 NodeImplFixed(AVRO_FIXED, name, NoLeaves(), NoLeafNames(), size) 00468 { } 00469 00470 SchemaResolution resolve(const Node &reader) const; 00471 00472 void printJson(std::ostream &os, int depth) const; 00473 00474 bool isValid() const { 00475 return ( 00476 (nameAttribute_.size() == 1) && 00477 (sizeAttribute_.size() == 1) 00478 ); 00479 } 00480 }; 00481 00482 template < class A, class B, class C, class D > 00483 inline void 00484 NodeImpl<A,B,C,D>::setLeafToSymbolic(int index, const NodePtr &node) 00485 { 00486 if(!B::hasAttribute) { 00487 throw Exception("Cannot change leaf node for nonexistent leaf"); 00488 } 00489 00490 NodePtr &replaceNode = const_cast<NodePtr &>(leafAttributes_.get(index)); 00491 if(replaceNode->name() != node->name()) { 00492 throw Exception("Symbolic name does not match the name of the schema it references"); 00493 } 00494 00495 NodePtr symbol(new NodeSymbolic); 00496 NodeSymbolic *ptr = static_cast<NodeSymbolic *> (symbol.get()); 00497 00498 ptr->setName(node->name()); 00499 ptr->setNode(node); 00500 replaceNode.swap(symbol); 00501 } 00502 00503 template < class A, class B, class C, class D > 00504 inline void 00505 NodeImpl<A,B,C,D>::printBasicInfo(std::ostream &os) const 00506 { 00507 os << type(); 00508 if(hasName()) { 00509 os << ' ' << nameAttribute_.get(); 00510 } 00511 00512 if(D::hasAttribute) { 00513 os << " " << sizeAttribute_.get(); 00514 } 00515 os << '\n'; 00516 int count = leaves(); 00517 count = count ? count : names(); 00518 for(int i= 0; i < count; ++i) { 00519 if( C::hasAttribute ) { 00520 os << "name " << nameAt(i) << '\n'; 00521 } 00522 if( type() != AVRO_SYMBOLIC && leafAttributes_.hasAttribute) { 00523 leafAt(i)->printBasicInfo(os); 00524 } 00525 } 00526 if(isCompound(type())) { 00527 os << "end " << type() << '\n'; 00528 } 00529 } 00530 00531 00532 inline NodePtr resolveSymbol(const NodePtr &node) 00533 { 00534 if(node->type() != AVRO_SYMBOLIC) { 00535 throw Exception("Only symbolic nodes may be resolved"); 00536 } 00537 boost::shared_ptr<NodeSymbolic> symNode = boost::static_pointer_cast<NodeSymbolic>(node); 00538 return symNode->getNode(); 00539 } 00540 00541 } // namespace avro 00542 00543 #endif