
.. |br| raw:: html

   <br />

.. Images

.. Links

.. =============================================

C++ Support Classes
===================

A number of support classes exist within the common library that forms part of every FogLAMP plugin.

Reading
-------

The *Reading* class and the associated *Datapoint* and *DatapointValue* classes provide the mechanism within C++ classes to manipulated the reading asset data. The public part of the *Reading* class is currently defined as follows;

.. code-block:: C

  class Reading {
          public:
                  Reading(const std::string& asset, Datapoint *value);
                  Reading(const std::string& asset, std::vector<Datapoint *> values);
                  Reading(const std::string& asset, std::vector<Datapoint *> values, const std::string& ts);
                  Reading(const Reading& orig);

                  ~Reading();
                  void                            addDatapoint(Datapoint *value);
                  Datapoint                       *removeDatapoint(const std::string& name);
                  std::string                     toJSON(bool minimal = false) const;
                  std::string                     getDatapointsJSON() const;
                  // Return AssetName
                  const std::string&              getAssetName() const { return m_asset; };
                  // Set AssetName
                  void                            setAssetName(std::string assetName) { m_asset = assetName; };
                  unsigned int                    getDatapointCount() { return m_values.size(); };
                  void                            removeAllDatapoints();
                  // Return Reading datapoints
                  const std::vector<Datapoint *>  getReadingData() const { return m_values; };
                  // Return reference to Reading datapoints
                  std::vector<Datapoint *>&       getReadingData() { return m_values; };
                  unsigned long                   getId() const { return m_id; };
                  unsigned long                   getTimestamp() const { return (unsigned long)m_timestamp.tv_sec; };
                  unsigned long                   getUserTimestamp() const { return (unsigned long)m_userTimestamp.tv_sec; };
                  void                            setId(unsigned long id) { m_id = id; };
                  void                            setTimestamp(unsigned long ts) { m_timestamp.tv_sec = (time_t)ts; };
                  void                            setTimestamp(struct timeval tm) { m_timestamp = tm; };
                  void                            setTimestamp(const std::string& timestamp);
                  void                            getTimestamp(struct timeval *tm) { *tm = m_timestamp; };
                  void                            setUserTimestamp(unsigned long uTs) { m_userTimestamp.tv_sec = (time_t)uTs; };
                  void                            setUserTimestamp(struct timeval tm) { m_userTimestamp = tm; };
                  void                            setUserTimestamp(const std::string& timestamp);
                  void                            getUserTimestamp(struct timeval *tm) { *tm = m_userTimestamp; };

                  typedef enum dateTimeFormat { FMT_DEFAULT, FMT_STANDARD, FMT_ISO8601 } readingTimeFormat;

                  // Return Reading asset time - ts time
                  const std::string getAssetDateTime(readingTimeFormat datetimeFmt = FMT_DEFAULT, bool addMs = true) const;
                  // Return Reading asset time - user_ts time
                  const std::string getAssetDateUserTime(readingTimeFormat datetimeFmt = FMT_DEFAULT, bool addMs = true) const;
  }

The *Reading* class contains a number of items that are mapped to the JSON representation of data that is sent to the FogLAMP storage service and are used by the various services and plugins within FogLAMP.

  - **Asset Name**: The name of the asset. The asset name is set in the constructor of the reading and retrieved via the *getAssetName()* method.

  - **Timestamp**: The timestamp when the reading was first seen within FogLAMP.

  - **User Timestamp**: The timestamp for the actual data in the reading. This may differ from the value of Timestamp if the device itself is able to supply a timestamp value.

  - **Datapoints**: The actual data of a reading stored in a Datapoint class.

The *Datapoint* class provides a name for each data point within a *Reading* and the tagged type data for the reading value. The public definition of the *Datapoint* class is as follows;

.. code-block:: C

  class Datapoint {
          public:
                  /**
                   * Construct with a data point value
                   */
                  Datapoint(const std::string& name, DatapointValue& value) : m_name(name), m_value(value);
                  ~Datapoint();
                  /**
                   * Return asset reading data point as a JSON
                   * property that can be included within a JSON
                   * document.
                   */
                  std::string     toJSONProperty();
                  const std::string getName() const;
                  void setName(std::string name);
                  const DatapointValue getData() const;
                  DatapointValue& getData();
  }

Closely associated with the *Datapoint* is the *DatapointValue* which uses a tagged union to store the values. The public definition of the *DatapointValue*  is as follows;

.. code-block:: C

   class DatapointValue {
           public:
                   /**
                    * Construct with a string
                    */
                   DatapointValue(const std::string& value)
                   {
                           m_value.str = new std::string(value);
                           m_type = T_STRING;
                   };
                   /**
                    * Construct with an integer value
                    */
                   DatapointValue(const long value)
                   {
                           m_value.i = value;
                           m_type = T_INTEGER;
                   };
                   /**
                    * Construct with a floating point value
                    */
                   DatapointValue(const double value)
                   {
                           m_value.f = value;
                           m_type = T_FLOAT;
                   };
                   /**
                    * Construct with an array of floating point values
                    */
                   DatapointValue(const std::vector<double>& values)
                   {
                           m_value.a = new std::vector<double>(values);
                           m_type = T_FLOAT_ARRAY;
                   };

                   /**
                    * Construct with an array of Datapoints
                    */
                   DatapointValue(std::vector<Datapoint*>*& values, bool isDict)
                   {
                           m_value.dpa = values;
                           m_type = isDict? T_DP_DICT : T_DP_LIST;
                   }

                   /**
                    * Construct with an Image
                    */
                   DatapointValue(const DPImage& value)
                   {
                           m_value.image = new DPImage(value);
                           m_type = T_IMAGE;
                   }

                   /**
                    * Construct with a DataBuffer
                    */
                   DatapointValue(const DataBuffer& value)
                   {
                           m_value.dataBuffer = new DataBuffer(value);
                           m_type = T_DATABUFFER;
                   }

                   /**
                    * Construct with an Image Pointer, the
                    * image becomes owned by the datapointValue
                    */
                   DatapointValue(DPImage *value)
                   {
                           m_value.image = value;
                           m_type = T_IMAGE;
                   }

                   /**
                    * Construct with a DataBuffer
                    */
                   DatapointValue(DataBuffer *value)
                   {
                           m_value.dataBuffer = value;
                           m_type = T_DATABUFFER;
                   }

                   /**
                    * Construct with a 2 dimensional  array of floating point values
                    */
                   DatapointValue(const std::vector< std::vector<double> >& values)
                   {
                           m_value.a2d = new std::vector< std::vector<double> >();
                           for (auto row : values)
                           {
                                   m_value.a2d->push_back(std::vector<double>(row));
                           }
                           m_type = T_2D_FLOAT_ARRAY;
                   };

                   /**
                    * Copy constructor
                    */
                   DatapointValue(const DatapointValue& obj);

                   /**
                    * Assignment Operator
                    */
                   DatapointValue& operator=(const DatapointValue& rhs);

                   /**
                    * Destructor
                    */
                   ~DatapointValue();

                   
                   /**
                    * Set the value of a datapoint, this may
                    * also cause the type to be changed.
                    * @param value	An integer value to set
                    */
                   void setValue(long value)
                   {
                           m_value.i = value;
                           m_type = T_INTEGER;
                   }

                   /**
                    * Set the value of a datapoint, this may
                    * also cause the type to be changed.
                    * @param value	A floating point value to set
                    */
                   void setValue(double value)
                   {
                           m_value.f = value;
                           m_type = T_FLOAT;
                   }

                   /** Set the value of a datapoint to be an image
                    * @param value The image to set in the data point
                    */
                   void setValue(const DPImage& value)
                   {
                           m_value.image = new DPImage(value);
                           m_type = T_IMAGE;
                   }

                   /**
                    * Return the value as a string
                    */
                   std::string	toString() const;

                   /**
                    * Return string value without trailing/leading quotes
                    */
                   std::string	toStringValue() const { return *m_value.str; };

                   /**
                    * Return long value
                    */
                   long toInt() const { return m_value.i; };
                   /**
                    * Return double value
                    */
                   double toDouble() const { return m_value.f; };

                   // Supported Data Tag Types
                   typedef enum DatapointTag
                   {
                           T_STRING,
                           T_INTEGER,
                           T_FLOAT,
                           T_FLOAT_ARRAY,
                           T_DP_DICT,
                           T_DP_LIST,
                           T_IMAGE,
                           T_DATABUFFER,
                           T_2D_FLOAT_ARRAY
                   } dataTagType;

                   /**
                    * Return the Tag type
                    */
                   dataTagType getType() const
                   {
                           return m_type;
                   }

                   std::string getTypeStr() const
                   {
                           switch(m_type)
                           {
                                   case T_STRING: return std::string("STRING");
                                   case T_INTEGER: return std::string("INTEGER");
                                   case T_FLOAT: return std::string("FLOAT");
                                   case T_FLOAT_ARRAY: return std::string("FLOAT_ARRAY");
                                   case T_DP_DICT: return std::string("DP_DICT");
                                   case T_DP_LIST: return std::string("DP_LIST");
                                   case T_IMAGE: return std::string("IMAGE");
                                   case T_DATABUFFER: return std::string("DATABUFFER");
                                   case T_2D_FLOAT_ARRAY: return std::string("2D_FLOAT_ARRAY");
                                   default: return std::string("INVALID");
                           }
                   }

                   /**
                    * Return array of datapoints
                    */
                   std::vector<Datapoint*>*& getDpVec()
                   {
                           return m_value.dpa;
                   }

                   /**
                    * Return array of float
                    */
                   std::vector<double>*& getDpArr()
                   {
                           return m_value.a;
                   }

                   /**
                    * Return 2D array of float
                    */
                   std::vector<std::vector<double> >*& getDp2DArr()
                   {
                           return m_value.a2d;
                   }

                   /**
                    * Return the Image
                    */
                   DPImage *getImage()
                   {
                           return m_value.image;
                   }

                   /**
                    * Return the DataBuffer
                    */
                   DataBuffer *getDataBuffer()
                   {
                           return m_value.dataBuffer;
                   }
   };

The *DatapointValue* can store data in as a number of types

 +------------------+---------------------------------------------+
 | Type             | C++ Representation                          |
 +==================+=============================================+
 | T_STRING         | Pointer to std::string                      |
 +------------------+---------------------------------------------+
 | T_INTEGER        | long                                        |
 +------------------+---------------------------------------------+
 | T_FLOAT          | double                                      |
 +------------------+---------------------------------------------+
 | T_FLOAT_ARRAY    | Pointer to std::vector<double>              |
 +------------------+---------------------------------------------+
 | T_2D_FLOAT_ARRAY | Pointer to std::vector<std::vector<double>> |
 +------------------+---------------------------------------------+
 | T_DP_DICT        | Pointer to std::vector<Datapoint \*>        |
 +------------------+---------------------------------------------+
 | T_DP_LIST        | Pointer to std::vector<Datapoint \*>        |
 +------------------+---------------------------------------------+
 | T_IMAGE          | Pointer to DPImage                          |
 +------------------+---------------------------------------------+
 | T_DATABUFFER     | Pointer to DataBuffer                       |
 +------------------+---------------------------------------------+

Configuration Category
----------------------

The *ConfigCategory* class is a support class for managing configuration information within a plugin and is passed to the plugin entry points. The public definition of the class is as follows;

.. code-block:: C

  class ConfigCategory {
          public:
                  enum ItemType {
                          UnknownType,
                          StringItem,
                          EnumerationItem,
                          JsonItem,
                          BoolItem,
                          NumberItem,
                          DoubleItem,
                          ScriptItem,
                          CategoryType,
                          CodeItem
                  };

                  ConfigCategory(const std::string& name, const std::string& json);
                  ConfigCategory() {};
                  ConfigCategory(const ConfigCategory& orig);
                  ~ConfigCategory();
                  void                            addItem(const std::string& name, const std::string description,
                                                          const std::string& type, const std::string def,
                                                          const std::string& value);
                  void                            addItem(const std::string& name, const std::string description,
                                                          const std::string def, const std::string& value,
                                                          const std::vector<std::string> options);
                  void                            removeItems();
                  void                            removeItemsType(ItemType type);
                  void                            keepItemsType(ItemType type);
                  bool                            extractSubcategory(ConfigCategory &subCategories);
                  void                            setDescription(const std::string& description);
                  std::string                     getName() const;
                  std::string                     getDescription() const;
                  unsigned int                    getCount() const;
                  bool                            itemExists(const std::string& name) const;
                  bool                            setItemDisplayName(const std::string& name, const std::string& displayName);
                  std::string                     getValue(const std::string& name) const;
                  std::string                     getType(const std::string& name) const;
                  std::string                     getDescription(const std::string& name) const;
                  std::string                     getDefault(const std::string& name) const;
                  bool                            setDefault(const std::string& name, const std::string& value);
                  std::string                     getDisplayName(const std::string& name) const;
                  std::vector<std::string>        getOptions(const std::string& name) const;
                  std::string                     getLength(const std::string& name) const;
                  std::string                     getMinimum(const std::string& name) const;
                  std::string                     getMaximum(const std::string& name) const;
                  bool                            isString(const std::string& name) const;
                  bool                            isEnumeration(const std::string& name) const;
                  bool                            isJSON(const std::string& name) const;
                  bool                            isBool(const std::string& name) const;
                  bool                            isNumber(const std::string& name) const;
                  bool                            isDouble(const std::string& name) const;
                  bool                            isDeprecated(const std::string& name) const;
                  std::string                     toJSON(const bool full=false) const;
                  std::string                     itemsToJSON(const bool full=false) const;
                  ConfigCategory&                 operator=(ConfigCategory const& rhs);
                  ConfigCategory&                 operator+=(ConfigCategory const& rhs);
                  void                            setItemsValueFromDefault();
                  void                            checkDefaultValuesOnly() const;
                  std::string                     itemToJSON(const std::string& itemName) const;
                  enum ItemAttribute              { ORDER_ATTR, READONLY_ATTR, MANDATORY_ATTR, FILE_ATTR};
                  std::string                     getItemAttribute(const std::string& itemName,
                                                                   ItemAttribute itemAttribute) const;
  }

Although *ConfigCategory* is a complex class, only a few of the methods are commonly used within a plugin

  - **itemExists:** - used to test if an expected configuration item exists within the configuration category.
  - **getValue:** - return the value of a configuration item from within the configuration category
  - **isBool:** - tests if a configuration item is of boolean type
  - **isNumber:** - tests if a configuration item is a number
  - **isDouble:** - tests if a configuration item is valid to be represented as a double
  - **isString:** - tests if a configuration item is a string

Logger
------

The *Logger* class is used to write entries to the syslog system within FogLAMP. A singleton *Logger* exists which can be obtained using the following code snippet;

.. code-block:: C

  Logger *logger = Logger::getLogger();
  logger->error("An error has occurred within the plugin processing");


It is then possible to log messages at one of five different log levels; *debug*, *info*, *warn*, *error* or *fatal*. Messages may be logged using standard printf formatting strings. The public definition of the *Logger* class is as follows;

.. code-block:: C

  class Logger {
          public:
                  Logger(const std::string& application);
                  ~Logger();
                  static Logger *getLogger();
                  void debug(const std::string& msg, ...);
                  void printLongString(const std::string&);
                  void info(const std::string& msg, ...);
                  void warn(const std::string& msg, ...);
                  void error(const std::string& msg, ...);
                  void fatal(const std::string& msg, ...);
                  void setMinLevel(const std::string& level);
  };

The various log levels should be used as follows;

  - **debug**: should be used to output messages that are relevant only to a programmer that is debugging the plugin.
  - **info**: should be used for information that is meaningful to the end users, but should not normally be logged.
  - **warn**: should be used for warning messages that will normally be logged but reflect a condition that does not prevent the plugin from operating.
  - **error**: should be used for conditions that cause a temporary failure in processing within the plugin.
  - **fatal**: should be used for conditions that cause the plugin to fail processing permanently, possibly requiring a restart of the microservice in order to resolve.
