DynamicObject.h

Go to the documentation of this file.
00001 /*
00002  * The information in this file is
00003  * Copyright(c) 2007 Ball Aerospace & Technologies Corporation
00004  * and is subject to the terms and conditions of the
00005  * GNU Lesser General Public License Version 2.1
00006  * The license text is available from   
00007  * http://www.gnu.org/licenses/lgpl.html
00008  */
00009 
00010 #ifndef DYNAMICOBJECT_H
00011 #define DYNAMICOBJECT_H
00012 
00013 #include "DataVariant.h"
00014 #include "DataVariantValidator.h"
00015 #include "Serializable.h"
00016 #include "Subject.h"
00017 
00018 #include <string>
00019 #include <vector>
00020 
00021 class DataVariant;
00022 class QRegExp;
00023 
00024 /**
00025  * Dynamic extension of class attributes
00026  *
00027  * Dynamic Object refers to a class that allows attributes to be 
00028  * added during runtime.  Many classes extend the Dynamic Object
00029  * to provide future support for new attributes without changing
00030  * the class specification.
00031  *
00032  * This subclass of Subject will notify upon the following conditions:
00033  * - The following methods are called: setAttribute(), setAttributeByPath(),
00034  *   adoptAttribute(), adoptAttributeByPath(), merge(), removeAttribute(),
00035  *   removeAttributeByPath(), clear().
00036  * - %Any of the objects within the DynamicObject post a notification.
00037  *   These notifications will be passed on to any observers of the
00038  *   DynamicObject
00039  * - Everything else documented in Subject.
00040  */
00041 class DynamicObject : public Subject, public Serializable
00042 {
00043 public:
00044    /**
00045     * Emitted just after a new attribute is added with
00046     * boost::any<std::pair<std::string, DataVariant*> > containing the
00047     * attribute name and value.
00048     */
00049    SIGNAL_METHOD(DynamicObject, AttributeAdded)
00050 
00051    /**
00052     * Emitted just after an existing attribute is modified with
00053     * boost::any<std::pair<std::string, DataVariant*> > containing the
00054     * attribute name and the new value.
00055     */
00056    SIGNAL_METHOD(DynamicObject, AttributeModified)
00057 
00058    /**
00059     * Emitted just before an existing attribute is removed with
00060     * boost::any<std::pair<std::string, DataVariant*> > containing the
00061     * name and value of the attribute that will be removed.\   The attribute
00062     * value is guaranteed to be valid when the signal is emitted.
00063     */
00064    SIGNAL_METHOD(DynamicObject, AttributeRemoved)
00065 
00066    /**
00067     * Emitted just before the dynamic object is cleared.\   All existing
00068     * attribute values are guaranteed to be valid when the signal is emitted.
00069     */
00070    SIGNAL_METHOD(DynamicObject, Cleared)
00071 
00072    /**
00073     * Sets attributes from those of another dynamic object.
00074     *
00075     * This method parses the given object's attributes, adding them to or
00076     * setting them in this object.  Any existing attributes that are not
00077     * contained in the given object are not removed.
00078     *
00079     * @param   pObject
00080     *          The object from which to set this object's attributes.
00081     *          Cannot be \c NULL.
00082     *
00083     * @notify  This method will notify Subject::signalModified once for each
00084     *          attribute which gets merged. The parameters will depend on
00085     *          the attribute modified.
00086     *
00087     * @see setAttribute()
00088     */
00089    virtual void merge(const DynamicObject* pObject) = 0;
00090 
00091    /**
00092     * Sets attributes from those of another dynamic object.
00093     *
00094     * This method parses the given object's attributes, adopting them into
00095     * the destination object.  Any existing attributes that are not
00096     * contained in the given object are not removed. The attributes of
00097     * the given dynamic object will be modified in an undefined manner.
00098     *
00099     * This method is intended for use when the given object will be discarded
00100     * after being merged into the destination object and can be much faster
00101     * than using the merge() method which sets the attributes rather than 
00102     * adopting them.
00103     *
00104     * @param   pObject
00105     *          The object from which to adopt into this object's attributes.
00106     *          Cannot be \c NULL.
00107     *
00108     * @notify  This method will notify Subject::signalModified once for each
00109     *          attribute which gets adopted. The parameters will depend on
00110     *          the attribute modified.
00111     *
00112     * @see adoptAttribute()
00113     */
00114    virtual void adoptiveMerge(DynamicObject* pObject) = 0;
00115 
00116    /**
00117     * Creates a new attribute or sets an existing dynamic attribute.
00118     *
00119     * This method is preferred to adoptAttribute() unless
00120     * you are passing an already constructed DataVariant in
00121     * which case, adoptAttribute() will be faster because
00122     * it avoids a deep copy.
00123     *
00124     * @param   name
00125     *          The name of the attribute to set the value.  If an attribute
00126     *          with the given name does not exist, an attribute is added.
00127     * @param   value
00128     *          The attribute's value.
00129     *
00130     * @return  Returns \c true if the attributes was successfully created or set,
00131     *          otherwise \c false.
00132     *
00133     * @notify  This method will notify Subject::signalModified.
00134     *
00135     * @see adoptAttribute()
00136     */
00137    template<class T>
00138    bool setAttribute(const std::string& name, const T& value)
00139    {
00140       DataVariant temp(value);
00141       return adoptAttribute(name, temp);
00142    }
00143 
00144    /**
00145     * Creates a new attribute or sets an existing dynamic attribute.
00146     *
00147     * This method should not be used; generally setAttribute() is
00148     * preferred. This method and setAttribute() have identical
00149     * performance characteristics and setAttribute() is easier to
00150     * call.  This method is faster than setAttribute() though if
00151     * you have an already constructed DataVariant and is
00152     * preferred to setAttribute() in this case.
00153     *  
00154     * @param   name
00155     *          The name of the attribute to set the value.  If an attribute
00156     *          with the given name does not exist, an attribute is added.
00157     * @param   value
00158     *          A variant holding the attribute's value. On return, this will 
00159     *          contain the value previously stored in the DynamicObject.
00160     *          If the value did not previously exist in the DynamicObject, 
00161     *          then this will contain an invalid DataVariant.
00162     *
00163     * @return  Returns \c true if the attributes was successfully created or set,
00164     *          otherwise \c false.
00165     *
00166     * @notify  This method will notify Subject::signalModified.
00167     *
00168     * @see setAttribute()
00169     */
00170    virtual bool adoptAttribute(const std::string& name, DataVariant& value) = 0;
00171    
00172    /**
00173     * Sets the value within the DynamicObject hierarchy as described in the path.
00174     *
00175     * This method will create DynamicObjects as needed to set the value.
00176     * This method is preferred to adoptAttributeByPath() unless
00177     * you are passing an already constructed DataVariant in
00178     * which case, adoptAttributeByPath() will be faster because
00179     * it avoids a deep copy.
00180     *
00181     * @param   path
00182     *          The path of names within names for the DynamicObjects,
00183     *          separated by '/'.  A slash in the name can be represented by
00184     *          escaping the slash with another slash (e.g. '//').  If the path
00185     *          ends in a single slash, it will be ignored.
00186     * @param   value
00187     *          The value to set into the DynamicObject.
00188     *
00189     * @return  Returns \c true if the operation was a success, \c false otherwise.
00190     *          This method will fail if any object along the path already exists
00191     *          but is not a DynamicObject.
00192     *
00193     * @notify  This method will notify Subject::signalModified.
00194     *
00195     * @see adoptAttributeByPath()
00196     */
00197    template<class T>
00198    bool setAttributeByPath(const std::string& path, const T& value)
00199    {
00200       DataVariant temp(value);
00201       return adoptAttributeByPath(path, temp);
00202    }
00203 
00204    /**
00205     * Sets the value within the DynamicObject hierarchy as described in the path.
00206     *
00207     * This method should not be used; generally setAttributeByPath() is
00208     * preferred. This method and setAttributeByPath() have identical
00209     * performance characteristics and setAttributeByPath() is easier to
00210     * call.  This method is faster than setAttributeByPath() though if
00211     * you have an already constructed DataVariant and is
00212     * preferred to setAttributeByPath() in this case.
00213     *
00214     * @param   path
00215     *          The path of names within names for the DynamicObjects,
00216     *          separated by '/'.  A slash in the name can be represented by
00217     *          escaping the slash with another slash (e.g. '//').  If the path
00218     *          ends in a single slash, it will be ignored.
00219     * @param   value
00220     *          The value to set into the DynamicObject. On return, this will
00221     *          contain the value previously stored in the DynamicObject.  If
00222     *          the value did not previously exist in the DynamicObject, then
00223     *          this will contain an invalid DataVariant.
00224     *
00225     * @return  Returns \c true if the operation was a success, \c false otherwise.
00226     *          This method will fail if any object along the path already exists
00227     *          but is not a DynamicObject.
00228     *
00229     * @notify  This method will notify Subject::signalModified.
00230     *
00231     * @see setAttributeByPath()
00232     */
00233    virtual bool adoptAttributeByPath(const std::string& path, DataVariant& value) = 0;
00234 
00235    /**
00236     * Sets the value within the DynamicObject hierarchy as described in the path.
00237     *
00238     * This method will create DynamicObjects as needed to set the value.
00239     * This method is preferred to adoptAttributeByPath() unless
00240     * you are passing an already constructed DataVariant in
00241     * which case, adoptAttributeByPath() will be faster because
00242     * it avoids a deep copy.
00243     *
00244     * @param pComponents
00245     *        An array of path components to the desired object as std::strings.  Must end with
00246     *        END_METADATA_NAME.
00247     *
00248     * @param value
00249     *        The value to set into the DynamicObject.
00250     *
00251     * @return Returns \c true if the operation was a success, \c false otherwise.
00252     *         This method will fail if any object along the path already exists
00253     *         but is not a DynamicObject.
00254     *
00255     * @notify  This method will notify Subject::signalModified.
00256     *
00257     * @see adoptAttributeByPath()
00258     */
00259    template<class T>
00260    bool setAttributeByPath(const std::string pComponents[], const T& value)
00261    {
00262       DataVariant temp(value);
00263       return adoptAttributeByPath(pComponents, temp);
00264    }
00265 
00266    /**
00267     * Sets the value within the DynamicObject hierarchy as described in the path.
00268     *
00269     * This method should not be used; generally setAttributeByPath() is
00270     * preferred. This method and setAttributeByPath() have identical
00271     * performance characteristics and setAttributeByPath() is easier to
00272     * call.  This method is faster than setAttributeByPath() though if
00273     * you have an already constructed DataVariant and is
00274     * preferred to setAttributeByPath() in this case.
00275     *
00276     * @param pComponents
00277     *        An array of path components to the desired object as std::strings.  Must end with
00278     *        END_METADATA_NAME.
00279     *
00280     * @param value
00281     *        The value to set into the DynamicObject. On return, this will contain the value previously stored in the DynamicObject.
00282     *        If the value did not previously exist in the DynamicObject, then this will contain an invalid DataVariant.
00283     *
00284     * @return Returns \c true if the operation was a success, \c false otherwise.
00285     *         This method will fail if any object along the path already exists
00286     *         but is not a DynamicObject.
00287     *
00288     * @notify  This method will notify Subject::signalModified.
00289     *
00290     * @see setAttributeByPath()
00291     */
00292    virtual bool adoptAttributeByPath(const std::string pComponents[], DataVariant& value) = 0;
00293 
00294    /**
00295     * Returns an attribute value.
00296     *
00297     * @param   name
00298     *          The name of the attribute for which to get the value.
00299     *
00300     * @return  A variant holding the attributes value. The variant will be
00301     *          invalid if the attribute did not exist.
00302     *
00303     * @see     DataVariant::isValid()
00304     */
00305    virtual const DataVariant& getAttribute(const std::string& name) const = 0;
00306 
00307    /**
00308     * Returns an attribute value.
00309     *
00310     * @param   name
00311     *          The name of the attribute for which to get the value.
00312     *
00313     * @return  A variant holding the attributes value. The variant will be
00314     *          invalid if the attribute did not exist.
00315     *
00316     * @see     DataVariant::isValid()
00317     */
00318    virtual DataVariant& getAttribute(const std::string& name) = 0;
00319 
00320    /**
00321     * Get the value within the DynamicObject hierarchy
00322     * as described in the path.
00323     *
00324     * @param   path
00325     *          The path of names within names for the DynamicObjects,
00326     *          separated by '/'.  A slash in the name can be represented by
00327     *          escaping the slash with another slash (e.g. '//').  If the path
00328     *          ends in a single slash, it will be ignored.
00329     *
00330     * @return  A variant holding the attributes value. The variant will be
00331     *          empty if the attribute did not exist.
00332     */
00333    virtual const DataVariant& getAttributeByPath(const std::string& path) const = 0;
00334 
00335    /**
00336     * Get the value within the DynamicObject hierarchy
00337     * as described in the path.
00338     *
00339     * @param   path
00340     *          The path of names within names for the DynamicObjects,
00341     *          separated by '/'.  A slash in the name can be represented by
00342     *          escaping the slash with another slash (e.g. '//').  If the path
00343     *          ends in a single slash, it will be ignored.
00344     *
00345     * @return  A variant holding the attributes value. The variant will be
00346     *          empty if the attribute did not exist.
00347     */
00348    virtual DataVariant& getAttributeByPath(const std::string& path) = 0;
00349 
00350     /**
00351      * Get the value within the DynamicObject hierarchy
00352      * as described in the path.
00353      *
00354      * @param pComponents
00355      *        An array of path components to the desired object as std::strings.  Must end with
00356      *        END_METADATA_NAME.
00357      *
00358      * @return  A variant holding the attributes value. The variant will be
00359      *          empty if the attribute did not exist.
00360      */
00361    virtual const DataVariant& getAttributeByPath(const std::string pComponents[]) const = 0;
00362 
00363    /**
00364     * Get the value within the DynamicObject hierarchy
00365     * as described in the path.
00366     *
00367     * @param pComponents
00368     *        An array of path components to the desired object as std::strings.  Must end with
00369     *        END_METADATA_NAME.
00370     *
00371     * @return  A variant holding the attributes value. The variant will be
00372     *          empty if the attribute did not exist.
00373     */
00374    virtual DataVariant& getAttributeByPath(const std::string pComponents[]) = 0;
00375 
00376    /**
00377     * Retrieves the names of all attributes in the object.
00378     *
00379     * @param   attributeNames
00380     *          A vector of strings that is populated with the attribute names.
00381     *
00382     * @see     getNumAttributes()
00383     * @see     getAttribute()
00384     */
00385    virtual void getAttributeNames(std::vector<std::string>& attributeNames) const = 0;
00386 
00387    /**
00388     * Retrieves the total number of attributes in the object.
00389     *
00390     * @return  The number of attributes in the object.
00391     *
00392     * @see     getAttributeNames()
00393     */
00394    virtual unsigned int getNumAttributes() const = 0;
00395 
00396    /**
00397     * Searches the object for an attribute with a given name and/or value.
00398     *
00399     * @warning This method only searches this object's attributes and not
00400     *          any attributes of a child DynamicObject.
00401     *
00402     * @param   name
00403     *          The name of the attribute for which to search, which can be a
00404     *          fixed string or any regular expression supported by QRegExp.  If
00405     *          \em name is empty, then the first attribute found with the given
00406     *          value is returned.
00407     * @param   value
00408     *          The value of the attribute for which to search, which can be a
00409     *          fixed string or any regular expression supported by QRegExp.  If
00410     *          \em value is empty, then the first attribute found with the given
00411     *          name is returned.
00412     *
00413     * @return  Returns a const reference to the first attribute found with the
00414     *          given name and/or value.  A const reference to an invalid value
00415     *          is returned if both \em name and \em value are empty, or if this
00416     *          object does not have an attribute with the given name and/or
00417     *          value.
00418     *
00419     * @see     findFirstOf(const QRegExp&, const QRegExp&)
00420     */
00421    virtual const DataVariant& findFirstOf(const QRegExp& name, const QRegExp& value) const = 0;
00422 
00423    /**
00424     * Searches the object for an attribute with a given name and/or value.
00425     *
00426     * @warning This method only searches this object's attributes and not
00427     *          any attributes of a child DynamicObject.
00428     *
00429     * @param   name
00430     *          The name of the attribute for which to search, which can be a
00431     *          fixed string or any regular expression supported by QRegExp.  If
00432     *          \em name is empty, then the first attribute found with the given
00433     *          value is returned.
00434     * @param   value
00435     *          The value of the attribute for which to search, which can be a
00436     *          fixed string or any regular expression supported by QRegExp.  If
00437     *          \em value is empty, then the first attribute found with the given
00438     *          name is returned.
00439     *
00440     * @return  Returns a non-const reference to the first attribute found with
00441     *          the given name and/or value.  A non-const reference to an invalid
00442     *          value is returned if both \em name and \em value are empty, or if
00443     *          this object does not have an attribute with the given name and/or
00444     *          value.
00445     *
00446     * @see     findFirstOf(const QRegExp&, const QRegExp&) const
00447     */
00448    virtual DataVariant& findFirstOf(const QRegExp& name, const QRegExp& value) = 0;
00449 
00450    /**
00451     * Removes an attribute from the object.
00452     *
00453     * @param   name
00454     *          The name of the attribute to remove.
00455     *
00456     * @return  Returns \c true if the attribute was was successfully removed from the object,
00457     *          otherwise \c false.
00458     *
00459     * @notify This method will notify Subject::signalModified.
00460     *
00461     * @see     clear()
00462     */
00463    virtual bool removeAttribute(const std::string& name) = 0;
00464 
00465    /**
00466     * Removes an attribute from the object.
00467     *
00468     * @param pComponents
00469     *        An array of path components to the desired object as std::strings.  Must end with
00470     *        END_METADATA_NAME.
00471     *
00472     * @return  Returns \c true if the attribute was was successfully removed from the object,
00473     *          otherwise \c false.
00474     *
00475     * @notify This method will notify Subject::signalModified.
00476     *
00477     * @see     clear()
00478     */
00479    virtual bool removeAttributeByPath(const std::string pComponents[]) = 0;
00480 
00481    /**
00482     * Removes an attribute from the object.
00483     *
00484     * @param   path
00485     *          The path of names within names for the DynamicObjects,
00486     *          separated by '/'.  A slash in the name can be represented by
00487     *          escaping the slash with another slash (e.g. '//').  If the path
00488     *          ends in a single slash, it will be ignored.
00489     *
00490     * @return  Returns \c true if the attribute was was successfully removed from the object,
00491     *          otherwise \c false.
00492     *
00493     * @notify  This method will notify Subject::signalModified.
00494     *
00495     * @see     clear()
00496     */
00497    virtual bool removeAttributeByPath(const std::string& path) = 0;
00498 
00499    /**
00500     *  Compares all attributes in this DynamicObject with those of another
00501     *  DynamicObject.
00502     *
00503     *  @warning Based on the number of attributes present in the DynamicObject,
00504     *           calling this method could be time intensive.
00505     *
00506     *  @param   pObject
00507     *           The DynamicObject with which to compare attributes in this
00508     *           DynamicObject.  This method does nothing and returns \c false if
00509     *           \c NULL is passed in.
00510     *
00511     *  @return  Returns \c true if all attributes in \em pObject are present and
00512     *           have the same values as the attributes in this DynamicObject;
00513     *           otherwise returns \c false.
00514     */
00515    virtual bool compare(const DynamicObject* pObject) const = 0;
00516 
00517    /**
00518     * Erases all attributes in the object.
00519     *
00520     * @notify This method will notify Subject::signalModified.
00521     *
00522     * @see     remove()
00523     */
00524    virtual void clear() = 0;
00525 
00526 protected:
00527    /**
00528     * This should be destroyed by calling ObjectFactory::destroyObject.
00529     */
00530    virtual ~DynamicObject() {}
00531 };
00532 
00533 /**
00534  * \cond INTERNAL
00535  * These template specialization are required to allow these types to be put into a DataVariant.
00536  */
00537 template <> class VariantTypeValidator<DynamicObject> {};
00538 template <> class VariantTypeValidator<const DynamicObject> {};
00539 /// \endcond
00540 
00541 #endif   // DYNAMICOBJECT_H

Software Development Kit - Opticks 4.9.0 Build 16218