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