NodeImpl.hh

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