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